这是我参与8月更文挑战的第22天,活动详情查看:8月更文挑战
剑指 Offer 45. 把数组排成最小的数
题目
输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
示例 1:
输入: [10,2]
输出: "102"
示例 2:
输入: [3,30,34,5,9]
输出: "3033459"
提示:
0 < nums.length <= 100
说明:
- 输出结果可能非常大,所以你需要返回一个字符串而不是整数
- 拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0
方法一
排序:
自定义排序规则:
- 若拼接字符串 x + y > y + x,则 x “大于” y ;
- 若x+y<y+x,则x“小于”y;
证明:
字符串 xy < yx , yz < zy ,需证明 xz < zx 一定成立。
设十进制数 x, y, z 分别有 a, b, c 位,则有:
(左边是字符串拼接,右边是十进制数计算,两者等价)
xy = x * 10^b + y
yx = y * 10^a + x
则 xy < yx 可转化为:
x * 10^b + y < y * 10^a + x
x (10^b - 1) < y (10^a - 1)
x / (10^a - 1) < y / (10^b - 1) ①
同理, 可将 yz < zy 转化为:
y / (10^b - 1) < z / (10^c - 1) ②
将 ① ② 合并,整理得:
x / (10^a - 1) < y / (10^b - 1) < z / (10^c - 1)
x / (10^a - 1) < z / (10^c - 1)
x (10^c - 1) < z (10^a - 1)
x * 10^c + z < z * 10^a + x
∴ 可推出 xz < zx ,传递性证毕
class Solution {
public String minNumber(int[] nums) {
String[] ss = new String[nums.length];
for (int i = 0; i < nums.length; i ++ )
ss[i] = String.valueOf(nums[i]);
Arrays.sort(ss, (a, b)->{
String s1 = a + b, s2 = b + a;
return s1.compareTo(s2);
});
//字符串拼接用StringBuilder
StringBuilder res = new StringBuilder();
for (String s : ss)
res.append(s);
return res.toString();
}
}
剑指 Offer 46. 把数字翻译成字符串
题目
给定一个数字,我们按照如下规则把它翻译为字符串:0 翻译成 “a” ,1 翻译成 “b”,……,11 翻译成 “l”,……,25 翻译成 “z”。一个数字可能有多个翻译。请编程实现一个函数,用来计算一个数字有多少种不同的翻译方法。
示例 1:
输入: 12258
输出: 5
解释: 12258有5种不同的翻译,分别是"bccfi", "bwfi", "bczi", "mcfi"和"mzi"
提示:
0 <= num < 231
方法一
递归:
- 将给定的数字
num的每一位上的数字扣下来,存在集合中;接下来进行递归; - 每个位置上的数为
0~9,所以一定有对应的字母可以匹配,接着递归下一位 - 处了上一步中的一位一位递归,也可以尝试去两位递归,判断一下这两位数是不是小于26,即有字母匹配,有则进行递归,递归的入参
+2表示下一位已经匹配上; - 当入参的位数等于集合的大小时,说明全部匹配,方案数
+1
class Solution {
int res = 0;
List<Integer> nums = new ArrayList<>();
public int translateNum(int num) {
while(num != 0) {
nums.add(num % 10);
num /= 10;
}
Collections.sort(nums, (a, b)->{
return -1;
});
dfs(0);
return res;
}
void dfs(int u) {
if (u == nums.size()) {
res ++;
return;
}
dfs(u + 1);
if (u < nums.size() - 1) {
int t1 = nums.get(u), t2 = 0;
t2 = nums.get(u + 1);
int t = t1 * 10 + t2;
if (t < 26 && nums.get(u) != 0)
dfs(u + 2);
}
}
}
方法二
动态规划:
f[i]表示前i位的翻译方案,值表示为最大值- 转移方程:第
i位可以从第i-1、i-2位转移过来,i-1一定可以转移,i-2需要判断一下
class Solution {
public int translateNum(int num) {
List<Integer> nums = new ArrayList<>();
while(num != 0) {
nums.add(num % 10);
num /= 10;
}
Collections.sort(nums, (a, b)->{
return -1;
});
if (nums.size() <= 1) return 1;
int[] f = new int[nums.size() + 1];
f[0] = f[1] = 1;
for (int i = 2; i <= nums.size(); i ++ ) {
f[i] = f[i - 1];
if (nums.get(i - 1) + nums.get(i - 2) * 10 < 26 && nums.get(i - 2) != 0)
f[i] += f[i - 2];
}
return f[nums.size()];
}
}