Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 137 additions & 4 deletions solution/3500-3599/3517.Smallest Palindromic Rearrangement I/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,32 +86,165 @@ tags:

<!-- solution:start -->

### 方法一
### 方法一:计数

我们首先统计字符串中每个字符的出现次数,记录在哈希表或数组 $\textit{cnt}$ 中。由于字符串是回文字符串,因此每个字符的出现次数要么是偶数次,要么有且仅有一个字符出现奇数次。

接下来,我们从字典序最小的字符开始,依次将每个字符的一半次数添加到结果字符串的前半部分 $\textit{t}$ 中。如果某个字符出现了奇数次,我们将该字符记录为中间字符 $\textit{ch}$。最后,我们将 $\textit{t}$、$\textit{ch}$ 和 $\textit{t}$ 的反转拼接起来,得到最终的按字典序排列的最小回文排列。

时间复杂度 $O(n)$,其中 $n$ 是字符串的长度。空间复杂度 $O(|\Sigma|)$,其中 $|\Sigma|$ 是字符集的大小,本题中 $|\Sigma|=26$。

<!-- tabs:start -->

#### Python3

```python

class Solution:
def smallestPalindrome(self, s: str) -> str:
cnt = Counter(s)
t = []
ch = ""
for c in ascii_lowercase:
v = cnt[c] // 2
t.append(c * v)
cnt[c] -= v * 2
if cnt[c] == 1:
ch = c
ans = "".join(t)
ans = ans + ch + ans[::-1]
return ans
```

#### Java

```java

class Solution {
public String smallestPalindrome(String s) {
int[] cnt = new int[26];
for (char c : s.toCharArray()) {
cnt[c - 'a']++;
}

StringBuilder t = new StringBuilder();
String ch = "";

for (char c = 'a'; c <= 'z'; c++) {
int idx = c - 'a';
int v = cnt[idx] / 2;
if (v > 0) {
t.append(String.valueOf(c).repeat(v));
}
cnt[idx] -= v * 2;
if (cnt[idx] == 1) {
ch = String.valueOf(c);
}
}

String ans = t.toString();
ans = ans + ch + new StringBuilder(ans).reverse();
return ans;
}
}
```

#### C++

```cpp

class Solution {
public:
string smallestPalindrome(string s) {
vector<int> cnt(26);
for (char c : s) {
cnt[c - 'a']++;
}
string t = "";
string ch = "";
for (char c = 'a'; c <= 'z'; ++c) {
int v = cnt[c - 'a'] / 2;
if (v > 0) {
t.append(v, c);
}
cnt[c - 'a'] -= v * 2;
if (cnt[c - 'a'] == 1) {
ch = string(1, c);
}
}
string ans = t;
ans += ch;
string rev = t;
reverse(rev.begin(), rev.end());
ans += rev;
return ans;
}
};
```

#### Go

```go
func smallestPalindrome(s string) string {
cnt := make([]int, 26)
for i := 0; i < len(s); i++ {
cnt[s[i]-'a']++
}

t := make([]byte, 0, len(s)/2)
var ch byte
for c := byte('a'); c <= 'z'; c++ {
v := cnt[c-'a'] / 2
for i := 0; i < v; i++ {
t = append(t, c)
}
cnt[c-'a'] -= v * 2
if cnt[c-'a'] == 1 {
ch = c
}
}

totalLen := len(t) * 2
if ch != 0 {
totalLen++
}
var sb strings.Builder
sb.Grow(totalLen)

sb.Write(t)
if ch != 0 {
sb.WriteByte(ch)
}
for i := len(t) - 1; i >= 0; i-- {
sb.WriteByte(t[i])
}
return sb.String()
}
```

#### TypeScript

```ts
function smallestPalindrome(s: string): string {
const ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz';
const cnt = new Array<number>(26).fill(0);
for (const chKey of s) {
cnt[chKey.charCodeAt(0) - 97]++;
}

const t: string[] = [];
let ch = '';
for (let i = 0; i < 26; i++) {
const c = ascii_lowercase[i];
const v = Math.floor(cnt[i] / 2);
t.push(c.repeat(v));
cnt[i] -= v * 2;
if (cnt[i] === 1) {
ch = c;
}
}

let ans = t.join('');
ans = ans + ch + ans.split('').reverse().join('');
return ans;
}
```

<!-- tabs:end -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,32 +76,165 @@ tags:

<!-- solution:start -->

### Solution 1
### Solution 1: Counting

We first count the occurrence of each character in the string and record it in a hash table or array $\textit{cnt}$. Since the string is a palindrome, the count of each character is either even, or there is exactly one character with an odd count.

Next, starting from the lexicographically smallest character, we sequentially add half of each character's count to the first half of the result string $\textit{t}$. If a character appears an odd number of times, we record it as the middle character $\textit{ch}$. Finally, we concatenate $\textit{t}$, $\textit{ch}$, and the reverse of $\textit{t}$ to obtain the final lexicographically smallest palindromic rearrangement.

The time complexity is $O(n)$, where $n$ is the length of the string. The space complexity is $O(|\Sigma|)$, where $|\Sigma|$ is the size of the character set, which is $26$ in this problem.

<!-- tabs:start -->

#### Python3

```python

class Solution:
def smallestPalindrome(self, s: str) -> str:
cnt = Counter(s)
t = []
ch = ""
for c in ascii_lowercase:
v = cnt[c] // 2
t.append(c * v)
cnt[c] -= v * 2
if cnt[c] == 1:
ch = c
ans = "".join(t)
ans = ans + ch + ans[::-1]
return ans
```

#### Java

```java

class Solution {
public String smallestPalindrome(String s) {
int[] cnt = new int[26];
for (char c : s.toCharArray()) {
cnt[c - 'a']++;
}

StringBuilder t = new StringBuilder();
String ch = "";

for (char c = 'a'; c <= 'z'; c++) {
int idx = c - 'a';
int v = cnt[idx] / 2;
if (v > 0) {
t.append(String.valueOf(c).repeat(v));
}
cnt[idx] -= v * 2;
if (cnt[idx] == 1) {
ch = String.valueOf(c);
}
}

String ans = t.toString();
ans = ans + ch + new StringBuilder(ans).reverse();
return ans;
}
}
```

#### C++

```cpp

class Solution {
public:
string smallestPalindrome(string s) {
vector<int> cnt(26);
for (char c : s) {
cnt[c - 'a']++;
}
string t = "";
string ch = "";
for (char c = 'a'; c <= 'z'; ++c) {
int v = cnt[c - 'a'] / 2;
if (v > 0) {
t.append(v, c);
}
cnt[c - 'a'] -= v * 2;
if (cnt[c - 'a'] == 1) {
ch = string(1, c);
}
}
string ans = t;
ans += ch;
string rev = t;
reverse(rev.begin(), rev.end());
ans += rev;
return ans;
}
};
```

#### Go

```go
func smallestPalindrome(s string) string {
cnt := make([]int, 26)
for i := 0; i < len(s); i++ {
cnt[s[i]-'a']++
}

t := make([]byte, 0, len(s)/2)
var ch byte
for c := byte('a'); c <= 'z'; c++ {
v := cnt[c-'a'] / 2
for i := 0; i < v; i++ {
t = append(t, c)
}
cnt[c-'a'] -= v * 2
if cnt[c-'a'] == 1 {
ch = c
}
}

totalLen := len(t) * 2
if ch != 0 {
totalLen++
}
var sb strings.Builder
sb.Grow(totalLen)

sb.Write(t)
if ch != 0 {
sb.WriteByte(ch)
}
for i := len(t) - 1; i >= 0; i-- {
sb.WriteByte(t[i])
}
return sb.String()
}
```

#### TypeScript

```ts
function smallestPalindrome(s: string): string {
const ascii_lowercase = 'abcdefghijklmnopqrstuvwxyz';
const cnt = new Array<number>(26).fill(0);
for (const chKey of s) {
cnt[chKey.charCodeAt(0) - 97]++;
}

const t: string[] = [];
let ch = '';
for (let i = 0; i < 26; i++) {
const c = ascii_lowercase[i];
const v = Math.floor(cnt[i] / 2);
t.push(c.repeat(v));
cnt[i] -= v * 2;
if (cnt[i] === 1) {
ch = c;
}
}

let ans = t.join('');
ans = ans + ch + ans.split('').reverse().join('');
return ans;
}
```

<!-- tabs:end -->
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class Solution {
public:
string smallestPalindrome(string s) {
vector<int> cnt(26);
for (char c : s) {
cnt[c - 'a']++;
}
string t = "";
string ch = "";
for (char c = 'a'; c <= 'z'; ++c) {
int v = cnt[c - 'a'] / 2;
if (v > 0) {
t.append(v, c);
}
cnt[c - 'a'] -= v * 2;
if (cnt[c - 'a'] == 1) {
ch = string(1, c);
}
}
string ans = t;
ans += ch;
string rev = t;
reverse(rev.begin(), rev.end());
ans += rev;
return ans;
}
};
Loading