前言
昨天我在刷牛客的时候,看到一个牛友分享了百度二面的算法手撕题:将一个整数数组[a1,a2,a3,a4…]中的所有元素拼接起来,返回最大的值,我对该题很感兴趣,又参考了力扣 LCR 164. 破解闯关密码的解法,自己写了代码,如有错误,期望大佬纠正,万分感谢!
提示:以下是本篇文章正文内容,下面案例可供参考
一、寻找规律
假若有一个数组[3,30,34,5,9],怎么才能使其拼接最大呢?我们可以将整数转换为字符拼接比较,例如3和30,拼接结果有330和303,330比303大,因此3应该在30前面,我们从后往前遍历一次进行比较交换可以将拼接的第一位确定
从最后一位开始向前遍历第一轮遍历确定第一位的值
[ 3 , 30 , 34 , 5 , 9]
9和5拼接比较 ‘95’>‘59’ 进行交换后的结果[ 3 , 30 , 34 , 9 , 5 ]
‘934’>‘349’ 结果 [3 , 30 , 9 , 34 , 5]
…
第一轮后的结果[ 9 , 3 , 30 , 34 , 5 ]
我们发现每一轮确定一个位置,那么下一轮就要对[ 3 , 30 , 34 , 5 ]进行排序
…
当位置都确定后最大值也就出现了,我们很容易发现这是冒泡排序,和数组排序整数直接比较不同,该题我们比较的是拼接的字符串大小,而排序是一样的。而冒泡排序时间复杂度较高,我们选择用快速排序来进行排序
二、代码实现
public static String findMax(int[] arr) {
int n = arr.length;
String[] s = new String[n];
for (int i = 0; i < n; i++) {
s[i] = String.valueOf(arr[i]);
}
// 快速排序
quickSort(s, 0, n - 1);
StringBuilder stringBuilder = new StringBuilder();
for (String s1 : s) {
stringBuilder.append(s1);
}
return String.valueOf(stringBuilder);
}
private static void quickSort(String[] s, int l, int r) {
if (l >= r) return;
// l作为分区点,i为左指针,j为右指针
int i = l, j = r;
while (i < j) {
// 右指针向左遍历直到s[j]+s[l]>s[l]+s[j],需要先遍历右指针,当最后i==j时由于j先进行的遍历那么s[j]一定是要在前面的值,与分区点进行交换刚刚好
while (i < j && (s[j] + s[l]).compareTo(s[l] + s[j]) <= 0) {
--j;
}
;
// 左指针向左遍历直到s[i]+s[l]<s[l]+s[i]
while (i < j && (s[i] + s[l]).compareTo(s[l] + s[i]) >= 0) {
i++;
}
swap(s, i, j);
}
swap(s, l, j);
quickSort(s, l, i - 1);
quickSort(s, i + 1, r);
}
//元素交换
private static void swap(String[] s, int i, int j) {
String tmp = s[i];
s[i] = s[j];
s[j] = tmp;
}