Medium
题目描述
给你一个仅由数字组成的字符串 num。
返回可以由 num 中的数字形成的最大回文整数(以字符串形式返回)。该整数不应包含前导零。
注意:
- 你不需要使用
num中的所有数字,但必须至少使用一个数字。 - 数字可以重新排列。
示例 1:
输入:num = "444947137"
输出:"7449447"
解释:
使用 "444947137" 中的数字 "4449477" 来形成回文整数 "7449447"。
可以证明 "7449447" 是可以形成的最大回文整数。
示例 2:
输入:num = "00009"
输出:"9"
解释:
可以证明 "9" 是可以形成的最大回文整数。
注意返回的整数不应包含前导零。
约束条件:
1 <= num.length <= 10^5num由数字组成
解题思路
这道题要求构造最大的回文数,可以分为以下几个步骤:
统计频次:统计每个数字的出现次数
构造策略:
- 回文数的特点是左右对称,所以除了中间位置外,其他位置的数字必须成对出现
- 为了构造最大回文数,应该优先使用较大的数字
- 从数字9到1,如果某个数字出现次数≥2,就在左半部分放置该数字的一半
处理中间位置:如果存在出现奇数次的数字,选择其中最大的一个放在中间
特殊情况处理:
- 如果构造的左半部分全是0,说明只能选择一个非零数字作为结果
- 注意避免前导零的问题
构造结果:将左半部分 + 中间数字(如果有)+ 左半部分的逆序组合成最终回文数
时间复杂度主要在于遍历字符串统计频次,整体算法简洁高效。
代码实现
class Solution {
public:
string largestPalindromic(string num) {
vector<int> count(10, 0);
for (char c : num) {
count[c - '0']++;
}
string left = "";
string middle = "";
// 从9到0构造左半部分
for (int i = 9; i >= 0; i--) {
if (i == 0 && left.empty()) {
// 避免前导零,但0可以作为中间数字
continue;
}
// 成对使用数字构造左半部分
int pairs = count[i] / 2;
left += string(pairs, '0' + i);
count[i] -= pairs * 2;
}
// 找到最大的剩余数字作为中间数字
for (int i = 9; i >= 0; i--) {
if (count[i] > 0) {
middle = '0' + i;
break;
}
}
// 如果左半部分为空,只返回中间数字
if (left.empty()) {
return middle.empty() ? "0" : middle;
}
string right = left;
reverse(right.begin(), right.end());
return left + middle + right;
}
};
class Solution:
def largestPalindromic(self, num: str) -> str:
count = [0] * 10
for c in num:
count[int(c)] += 1
left = []
middle = ""
# 从9到0构造左半部分
for i in range(9, -1, -1):
if i == 0 and not left:
# 避免前导零
continue
# 成对使用数字构造左半部分
pairs = count[i] // 2
left.extend([str(i)] * pairs)
count[i] -= pairs * 2
# 找到最大的剩余数字作为中间数字
for i in range(9, -1, -1):
if count[i] > 0:
middle = str(i)
break
# 如果左半部分为空,只返回中间数字
if not left:
return middle if middle else "0"
left_str = ''.join(left)
right_str = left_str[::-1]
return left_str + middle + right_str
public class Solution {
public string LargestPalindromic(string num) {
int[] count = new int[10];
foreach (char c in num) {
count[c - '0']++;
}
StringBuilder left = new StringBuilder();
string middle = "";
// 从9到0构造左半部分
for (int i = 9; i >= 0; i--) {
if (i == 0 && left.Length == 0) {
// 避免前导零
continue;
}
// 成对使用数字构造左半部分
int pairs = count[i] / 2;
left.Append(new string((char)('0' + i), pairs));
count[i] -= pairs * 2;
}
// 找到最大的剩余数字作为中间数字
for (int i = 9; i >= 0; i--) {
if (count[i] > 0) {
middle = ((char)('0' + i)).ToString();
break;
}
}
// 如果左半部分为空,只返回中间数字
if (left.Length == 0) {
return string.IsNullOrEmpty(middle) ? "0" : middle;
}
string leftStr = left.ToString();
char[] rightArray = leftStr.ToCharArray();
Array.Reverse(rightArray);
string rightStr = new string(rightArray);
return leftStr + middle + rightStr;
}
}
var largestPalindromic = function(num) {
const count = new Array(10).fill(0);
for (let char of num) {
count[parseInt(char)]++;
}
let left = '';
let middle = '';
for (let i = 9; i >= 0; i--) {
if (i === 0 && left === '' && count[i] > 0) {
if (count[i] % 2 === 1) {
middle = '0';
}
continue;
}
if (count[i] >= 2) {
const pairs = Math.floor(count[i] / 2);
left += i.toString().repeat(pairs);
}
if (count[i] % 2 === 1 && middle === '') {
middle = i.toString();
}
}
if (left === '' && middle === '') {
return '0';
}
const result = left + middle + left.split('').reverse().join('');
return result;
};
复杂度分析
| 复杂度类型 | 值 | 说明 |
|---|---|---|
| 时间复杂度 | O(n) | n为字符串长度,需要遍历一次统计频次,构造过程为常数时间 |
| 空间复杂度 | O(1) | 除了结果字符串外,只使用了固定大小的计数数组 |
相关题目
- . Longest Palindrome (Easy)