目录
排序
1 把数组排成最小的数
剑指 Offer 45. 把数组排成最小的数
https://leetcode-cn.com/problems/ba-shu-zu-pai-cheng-zui-xiao-de-shu-lcof/
此题求拼接起来的最小数字,本质上是一个排序问题。设数组 nums 中任意两数字的字符串为 x 和 y ,则规定 排序判断规则 为:
- 若拼接字符串 x + y > y + x,则 x “大于” y ;
- 反之,若 x + y < y + x ,则 x “小于” y ;
x “小于” y 代表:排序完成后,数组中 x 应在 y 左边;“大于” 则反之。
根据以上规则,套用任何排序方法对 nums 执行排序即可。
复杂度分析:
- 时间复杂度 O(NlogN) : N 为最终返回值的字符数量( strs 列表的长度≤N );使用快排或内置函数的平均时间复杂度为 O(NlogN) ,最差为 O(N^2) 。
- 空间复杂度 O(N) : 字符串列表 strs 占用线性大小的额外空间。
1. 冒泡排序
2. 内置函数:
需定义排序规则:
- Python 定义在函数
sort_rule(x, y)中; - Java 定义为
(x, y) -> (x + y).compareTo(y + x); - C++ 定义为
(string& x, string& y){ return x + y < y + x; };
class Solution {
public String minNumber(int[] nums) {
String[] strs = new String[nums.length];
for(int i = 0; i < nums.length; i++)
strs[i] = String.valueOf(nums[i]);
Arrays.sort(strs, (x, y) -> (x + y).compareTo(y + x));
StringBuilder res = new StringBuilder();
for(String s : strs)
res.append(s);
return res.toString();
}
}
3. 快速排序:
需修改快速排序函数中的排序判断规则。字符串大小(字典序)对比的实现方法:
- Python/C++ 中可直接用
<,>; - Java 中使用函数
A.compareTo(B);
class Solution {
public String minNumber(int[] nums) {
String[] strs = new String[nums.length];
for(int i = 0; i < nums.length; i++)
strs[i] = String.valueOf(nums[i]);
quickSort(strs, 0, strs.length - 1);
StringBuilder res = new StringBuilder();
for(String s : strs)
res.append(s);
return res.toString();
}
void quickSort(String[] strs, int l, int r) {
if(l >= r) return;
int i = l, j = r;
String tmp = strs[i];
while(i < j) {
while((strs[j] + strs[l]).compareTo(strs[l] + strs[j]) >= 0 && i < j) j--;
while((strs[i] + strs[l]).compareTo(strs[l] + strs[i]) <= 0 && i < j) i++;
tmp = strs[i];
strs[i] = strs[j];
strs[j] = tmp;
}
strs[i] = strs[l];
strs[l] = tmp;
quickSort(strs, l, i - 1);
quickSort(strs, i + 1, r);
}
}

3.2 快排写法改进
class Solution {
public String minNumber(int[] nums) {
String[] strs = new String[nums.length];
for (int i = 0; i < nums.length; i++) {
strs[i] = String.valueOf(nums[i]);
}
quickSort(strs, 0, strs.length - 1);
StringBuilder res = new StringBuilder();
for (String s : strs)
res.append(s);
return res.toString();
}
public void quickSort(String[] strs, int low, int high) {
if (low < high) {
int middle = getMiddle(strs, low, high);
quickSort(strs, low, middle - 1);
quickSort(strs, middle + 1, high);
}
}
public int getMiddle(String[] strs, int low, int high) {
//数组的第一个数为基准元素
String temp = strs[low];
while (low < high) {
//从后向前找比基准小的数
while (low < high && (strs[high] + temp).compareTo(temp + strs[high]) >= 0)
high--;
//把比基准小的数移到低端
strs[low] = strs[high];
//从前向后找比基准大的数
while (low < high && (strs[low] + temp).compareTo(temp + strs[low]) <= 0)
low++;
//把比基准大的数移到高端
strs[high] = strs[low];
}
strs[low] = temp;
return low;
}
}
3.3 比较改进
不通过字符串,直接使用数字进行比较 同时考虑遇到后面的是0的情况必交换
class Solution {
public String minNumber(int[] nums) {
StringBuilder sb = new StringBuilder();
quickSort(nums,0, nums.length - 1);
for (int i = 0; i < nums.length; i++) {
sb.append(nums[i]);
}
return sb.toString();
}
public void quickSort(int[] strs, int low, int high) {
if (low < high) {
int middle = getMiddle(strs, low, high);
quickSort(strs, low, middle - 1);
quickSort(strs, middle + 1, high);
}
}
public int getMiddle(int[] strs, int low, int high) {
//数组的第一个数为基准元素
int temp = strs[low];
while (low < high) {
//从后向前找比基准小的数
while (low < high && strs[high] != 0 && (strs[high] * Math.pow(10, getNum(temp))+ temp >= temp * Math.pow(10, getNum( strs[high])) + strs[high]))
high--;
//把比基准小的数移到低端
strs[low] = strs[high];
//从前向后找比基准大的数
while (low < high && (strs[low] * Math.pow(10, getNum(temp))+ temp <= temp * Math.pow(10, getNum(strs[low])) + strs[low]))
low++;
//把比基准大的数移到高端
strs[high] = strs[low];
}
strs[low] = temp;
return low;
}
public int getNum(int a){
int t = 0;
while (a != 0){
a = a /10;
t++;
}
return t;
}
}

2 扑克牌中的顺子
剑指 Offer 61. 扑克牌中的顺子
https://leetcode-cn.com/problems/bu-ke-pai-zhong-de-shun-zi-lcof/
1. 排序 + 遍历
第一步:冒泡排序 如果遇到相同的 直接false
第二步:循环一遍找到有几个大小王(也就是有几个0)
第三步:比较最大值和最小值的差是否小于5 是则返回true 否则返回false
class Solution {
public boolean isStraight(int[] nums) {
int t = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == 0) t++;
}
for (int i = 0; i < nums.length - 1; i++) {
for (int j = 0; j < nums.length - i - 1; j++) {
if(nums[j] < nums[j+1])
swap(nums,j,j+1);
else if (nums[j] == nums[j+1] && nums[j]!=0)
return false;
}
}
if(nums[0] - nums[nums.length - t - 1] < 5) return true;
return false;
}
public void swap(int[] nums, int i, int j){
int t;
t = nums[i];
nums[i] = nums[j];
nums[j] = t;
}
}
2. 集合 Set + 遍历
- 遍历五张牌,遇到大小王(即 0 )直接跳过。
- 判别重复: 利用 Set 实现遍历判重, Set 的查找方法的时间复杂度为 O(1) ;(提升!)
- 获取最大 / 最小的牌: 借助辅助变量 ma 和 mi ,遍历统计即可。
class Solution {
public boolean isStraight(int[] nums) {
Set<Integer> repeat = new HashSet<>();
int max = 0, min = 14;
for(int num : nums) {
if(num == 0) continue; // 跳过大小王
max = Math.max(max, num); // 最大牌
min = Math.min(min, num); // 最小牌
if(repeat.contains(num)) return false; // 若有重复,提前返回 false
repeat.add(num); // 添加此牌至 Set
}
return max - min < 5; // 最大牌 - 最小牌 < 5 则可构成顺子
}
}
复杂度分析:
- 时间复杂度 O(N) = O(5) = O(1): 其中 N 为 nums 长度,本题中 N ≡ 5 ;遍历数组使用 O(N) 时间。
- 空间复杂度 O(N) = O(5) = O(1) : 用于判重的辅助 Set 使用 O(N) 额外空间。
3. 排序+遍历
class Solution {
public boolean isStraight(int[] nums) {
int joker = 0;
Arrays.sort(nums); // 数组排序
for(int i = 0; i < 4; i++) {
if(nums[i] == 0) joker++; // 统计大小王数量
else if(nums[i] == nums[i + 1]) return false; // 若有重复,提前返回 false
}
return nums[4] - nums[joker] < 5; // 最大牌 - 最小牌 < 5 则可构成顺子
}
}


本文介绍了一种特殊的排序算法应用案例,即将数组按特定规则排序以形成最小数值,及通过排序和遍历判断扑克牌是否能组成顺子的方法。文章提供了多种排序算法的实现细节,包括冒泡排序、快速排序等,并展示了如何通过集合Set优化判断过程。
1030

被折叠的 条评论
为什么被折叠?



