剑指 Offer 45. 把数组排成最小的数
题目描述
输入一个非负整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。
提示:
-
0
<
n
u
m
s
.
l
e
n
g
t
h
<
=
100
0 < nums.length <= 100
0<nums.length<=100
说明: - 输出结果可能非常大,所以你需要返回一个字符串而不是整数
- 拼接起来的数字可能会有前导 0,最后结果不需要去掉前导 0
error 写法 😭
这里记录一下第一次自己写的错误写法。
-
错误原因:排序时候,直接调用
o1.compareTo(o2));
(即,先按照 首位不相同位 升序,若相同再按照长度升序) -
错误代码
// WA Code class Solution { public String minNumber(int[] nums) { int n = nums.length; String[] s = new String[n]; // int[] to String[] for (int i = 0; i < n; i++) { s[i] = nums[i] + ""; } Arrays.sort(s, (o1, o2) -> o1.compareTo(o2)); // 排序规则不对(见下面的 错误示例) StringBuilder sb = new StringBuilder(); for (String cnt : s) { sb.append(cnt); } return sb.toString(); } }
-
错误示例
排序 🔥
参考 K佬题解
思路 🤔
- 需要将 n u m s nums nums 中每个元素转化为String 后,进行排序
- 排序规则
- 若拼接字符串
x + y > y + x
,则 x “大于” y ; - 反之,若
x + y < y + x
,则 x “小于” y ;
- 若拼接字符串
class Solution {
public String minNumber(int[] nums) {
// 1、将nums每个元素转换为String
int n = nums.length;
String[] arr = new String[n];
for (int i = 0; i < n; i++) {
arr[i] = Integer.toString(nums[i]);
}
System.out.println("Arrays.toString(arr) = " + Arrays.toString(arr));
// 2、对arr排序
Arrays.sort(arr, (o1, o2) -> (o1 + o2).compareTo(o2 + o1)); // 排序
System.out.println(Arrays.toString(arr));
StringBuilder sb = new StringBuilder();
for (String s : arr) {
sb.append(s);
}
return sb.toString();
}
}
- 时间复杂度: O ( n l o g n ) O(n logn) O(nlogn) (快排时间消耗)
- 时间复杂度:
O
(
n
)
O(n)
O(n) (
StringBuilder
占用的空间)
排序(自定义快排)⭐️
同上思路,但这里没有调用 JDK 中的 快排库函数,而是自定义实现了 快排。
class Solution {
public String minNumber(int[] nums) {
int n = nums.length;
String[] s = new String[n];
// int[] to String[]
for (int i = 0; i < n; i++) {
s[i] = nums[i] + "";
}
// 快排
quickSort(s, 0, n - 1);
StringBuilder sb = new StringBuilder();
for (String cnt : s) {
sb.append(cnt);
}
return sb.toString();
}
// 左闭右闭区间:[startIndex, endIndex]
void quickSort(String[] s, int startIndex, int endIndex) {
if (startIndex >= endIndex) {
return;
}
int index = partition(s, startIndex, endIndex);
// 分治
quickSort(s, startIndex, index - 1);
quickSort(s, index + 1, endIndex);
}
// 划分区间
int partition(String[] s, int startIndex, int endIndex) {
String pivot = s[startIndex];
int left = startIndex;
int right = endIndex;
while (left < right) {
while (left < right && (s[right] + pivot).compareTo(pivot + s[right]) >= 0) {
right--;
}
while (left < right && (s[left] + pivot).compareTo(pivot + s[left]) <= 0) {
left++;
}
// 交换
String temp = s[left];
s[left] = s[right];
s[right] = temp;
}
// 此时,left的位置 即为 pivot 的“最终”位置
s[startIndex] = s[left];
s[left] = pivot;
return left;
}
}
- 时间复杂度: O ( n l o g n ) O(n logn) O(nlogn) (快排时间消耗)
- 时间复杂度:
O
(
n
)
O(n)
O(n) (
StringBuilder
占用的空间)
剑指 Offer 61. 扑克牌中的顺子
题目描述
从若干副扑克牌中随机抽 5 张牌,判断是不是一个顺子,即这5张牌是不是连续的。2~10为数字本身,A为1,J为11,Q为12,K为13,而大、小王为 0 ,可以看成任意数字。A 不能视为 14。
限制:
- 数组长度为 5
- 数组的数取值为 [0, 13] .
Set 😉
思路 🤔
- 统计
n
u
m
s
nums
nums 中的
max
和min
; - 若极差
max - min >= 5
,则一定不可能构成顺子,直接返回false
即可; - 否则,使用
set
统计 n u m s nums nums 中除了“小王”之外的扑克牌- 如果除了“王”之外还有重复 牌(即,
set.size() + king < 5
),则不可能构成 顺子 - 否则,除了以上情况,才可以构成顺子。
- 如果除了“王”之外还有重复 牌(即,
class Solution {
public boolean isStraight(int[] nums) {
int kings = 0;
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
Set<Integer> set = new HashSet<>();
for (int i : nums) {
if (i == 0) kings++;
else {
set.add(i);
// 统计非0的max、min
min = Math.min(i, min);
max = Math.max(i, max);
}
}
// 极差 >= 5,一定不可能构成顺子
if (max - min >= 5) {
return false;
}
// 查看除了0以外是否还有重复的牌
return set.size() + kings == 5;
}
}
- 时间复杂度: O ( n ) O(n) O(n) (其中, n = = 5 n == 5 n==5)
- 时间复杂度:
O
(
n
)
O(n)
O(n)
排序 ⭐️
思路 🤔
- 排序;
- 先统计 j o k e r joker joker 的个数
- 从
i = joker
开始,向后遍历,若遇见相等(非王)元素,则直接返回 false - 最终,若极差大于等于5,则不可能构成顺子;否则,可以为顺子。
class Solution {
public boolean isStraight(int[] nums) {
// 排序
Arrays.sort(nums);
int jokers = 0;
int min = Integer.MAX_VALUE;
int max = Integer.MIN_VALUE;
// 找“王”的数量
for ( ; jokers < nums.length && nums[jokers] == 0; jokers++) {}
for (int i = jokers; i < nums.length; i++) {
// 统计非0(此时已经越过所有joker,必然非0)的max、min
min = Math.min(nums[i], min);
max = Math.max(nums[i], max);
// 除0以外,出现重复元素时,则不可以构成顺子
if (i > 0 && nums[i] == nums[i - 1]) {
return false;
}
}
return max - min < 5;
}
}
- 时间复杂度: O ( n l o g n ) O(n logn) O(nlogn) (快排时间消耗)
- 时间复杂度:
O
(
l
o
g
n
)
O(logn)
O(logn) (快排占用系统栈空间)