文章目录
排序分类/排序算法的分类
冒泡排序
介绍
模拟/思路讲解
数组转换成String类型输
代码1:
package Sort;
import java.lang.reflect.Array;
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int arr[] = {
3,9,-1,10,-2};//从小到大排序
//第一趟排序 就是将最大的数排在最后
int temp = 0;//临时变量
for (int i = 0; i < arr.length-1; i++) {
if (arr[i] > arr[i+1]){
temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
System.out.println("第一趟排序后的数组:");
//???toString
System.out.println(Arrays.toString(arr));
//第二趟排序 就是第二大的数排在倒数第二位
for (int i = 0; i < arr.length - 2; i++) {
if (arr[i] > arr[i+1]){
temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
System.out.println("第二趟排序后的数组:");
//???toString
System.out.println(Arrays.toString(arr));
//第三趟排序 就是将第三大的数排在倒数第三位
for (int i = 0; i < arr.length - 3; i++) {
if (arr[i] > arr[i+1]){
temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
System.out.println("第三趟排序后的数组:");
//???toString
System.out.println(Arrays.toString(arr));
//第四趟排序 就是将第四大的数排在倒数第三位
for (int i = 0; i < arr.length - 4; i++) {
if (arr[i] > arr[i+1]){
temp = arr[i];
arr[i] = arr[i+1];
arr[i+1] = temp;
}
}
System.out.println("第四趟排序后的数组:");
//???toString
System.out.println(Arrays.toString(arr));
}
}
代码2(优化
package Sort;
import java.lang.reflect.Array;
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int arr[] = {
3,9,-1,10,-2};//从小到大排序
//第一趟排序 就是将最大的数排在最后
int temp = 0;//临时变量
for (int i = 0; i < arr.length-1; i++) {
for (int j = 0; j < arr.length-1-i; j++) {
if (arr[j] > arr[j+1]){
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
System.out.println("第"+(i+1)+"趟排序后的数组:");
System.out.println(Arrays.toString(arr));
}
}
}
代码3(算法优化 --当次排序没有进行交换则退出循环
package Sort;
import java.lang.reflect.Array;
import java.util.Arrays;
public class BubbleSort {
public static void main(String[] args) {
int arr[] = {
3,-1,9,10,20};//从小到大排序
//第一趟排序 就是将最大的数排在最后
int temp = 0;//临时变量
boolean flag = false;
for (int i = 0; i < arr.length-1; i++) {
for (int j = 0; j < arr.length-1-i; j++) {
if (arr[j] > arr[j+1]){
flag = true;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
System.out.println("第"+(i+1)+"趟排序后的数组:");
System.out.println(Arrays.toString(arr));
if (!flag){
break;
}else {
flag = false;
}
}
}
}
代码4(封装为方法
代码5(检测冒泡排序时间复杂度
package Sort;
import java.lang.reflect.Array;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class BubbleSort {
public static void main(String[] args) {
// int arr[] = {3,-1,9,10,20};//从小到大排序
int[] arr = new int[80000];
for (int i = 0; i < 80000; i++) {
arr[i] = (int)(Math.random() * 8000000);//生成[0,8000000)的数
}
Date date1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str = simpleDateFormat.format(date1);
System.out.println("排序前的时间是="+date1Str);
//测试冒泡排序
bubbleSort(arr);
Date date2 = new Date();
String date2Str = simpleDateFormat.format(date2);
System.out.println("排序后的时间是="+date2Str);
}
public static void bubbleSort(int[] arr){
//第一趟排序 就是将最大的数排在最后
int temp = 0;//临时变量
boolean flag = false;
for (int i = 0; i < arr.length-1; i++) {
for (int j = 0; j < arr.length-1-i; j++) {
if (arr[j] > arr[j+1]){
flag = true;
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
// System.out.println("第"+(i+1)+"趟排序后的数组:");
// System.out.println(Arrays.toString(arr));
if (!flag){
break;
}else {
flag = false;
}
}
}
}
冒泡排序时间复杂度:O(n2 )
选择排序
选择排序思路:
图解流程:
代码1
package Sort;
import java.util.Arrays;
public class SelectSort {
public static void main(String[] args) {
int[] arr = {
101, 119, 34,1};
System.out.println("排序前:");
System.out.println(Arrays.toString(arr));
selectSort(arr);
}
public static void selectSort(int[] arr) {
//第1轮
int minIndex = 0;
int min = arr[0];
for (int i = 0 + 1; i < arr.length; i++) {
if (min > arr[i]) {
//说明假定的最小值不是最小的
min = arr[i]; //重置min
minIndex = i; //重置minIndex
}
}
// System.out.println("minIndex = "+minIndex);
// System.out.println("min = "+min);
//将最小值元素与arr[0] 两者交换
if (minIndex != 0){
arr[minIndex] = arr[0];
arr[0] = min;
}
System.out.println("第1轮后:");
System.out.println(Arrays.toString(arr));
//第2轮
minIndex = 1;
min = arr[1];
for (int i = 1 + 1; i < arr.length; i++) {
if (min > arr[i]) {
//说明假定的最小值不是最小的
min = arr[i]; //重置min
minIndex = i; //重置minIndex
}
}
//将最小值元素与arr[0] 两者交换
if (minIndex != 1){
arr[minIndex] = arr[1];
arr[1] = min;
}
System.out.println("第2轮后:");
System.out.println(Arrays.toString(arr));
//第3轮
minIndex = 3;
min = arr[3];
for (int i = 2 + 1; i < arr.length; i++) {
if (min > arr[i]) {
//说明假定的最小值不是最小的
min = arr[i]; //重置min
minIndex = i; //重置minIndex
}
}
//将最小值元素与arr[0] 两者交换
if (minIndex != 3){
arr[minIndex] = arr[2];
arr[2] = min;
}
System.out.println("第3轮后:");
System.out.println(Arrays.toString(arr));
}
}
代码2(优化算法
package Sort;
import java.util.Arrays;
public class SelectSort {
public static void main(String[] args) {
int[] arr = {
101, 119, 34,1,-1,90,123};
System.out.println("排序前:");
System.out.println(Arrays.toString(arr));
selectSort(arr);
System.out.println("排序后:");
System.out.println(Arrays.toString(arr));
}
public static void selectSort(int[] arr) {
for (int i = 0; i < arr.length-1; i++) {
//第1轮
int minIndex = i;
int min = arr[i];
for (int j = i + 1; j < arr.length; j++) {
if (min > arr[j]) {
//说明假定的最小值不是最小的
min = arr[j]; //重置min
minIndex = j; //重置minIndex
}
}
//将最小值元素与arr[0] 两者交换
if (minIndex != i){
arr[minIndex] = arr[i];
arr[i] = min;
}
// System.out.println("第"+(i+1)+"轮后:");
// System.out.println(Arrays.toString(arr));
}
}
}
选择排序的时间复杂度是O(n2 )
比冒泡排序快的原因:
多了个判断筛选,减小循环次数
代码3(计算时间复杂度
main内
//计算选择排序的时间复杂度
int[] arr = new int[80000];
for (int i = 0; i < 80000; i++) {
arr[i] = (int)(Math.random() * 8000000);//生成[0,8000000)的数
}
Date date1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str = simpleDateFormat.format(date1);
System.out.println("排序前的时间是="+date1Str);
//测试冒泡排序
selectSort(arr);
Date date2 = new Date();
String date2Str = simpleDateFormat.format(date2);
System.out.println("排序后的时间是="+date2Str);
插入排序
思想
思路图
代码
package Sort;
import java.util.Arrays;
public class InsertSort {
public static void main(String[] args) {
//从小到大
int[] arr = {
101,34,119,1,-1,89};
insertSort(arr);
}
public static void insertSort(int[] arr){
for (int i = 1; i < arr.length; i++) {
int insertVal = arr[i];
int insertIndex = i-1; //arr[1]前面数的下标
//1.insertIndex >= 0:保证不越界
//2.insertVal < arr[insertIndex]还没找到插入位置
while (insertIndex >= 0 && insertVal < arr[insertIndex]){
arr[insertIndex+1] = arr[insertIndex]; //将arr[insertIndex]后移
insertIndex--;//让arr[1]再和前面的数进行比较
}
//当退出while循环时 说明插入的位置找到 insertIndex+1(因为
// 1.insertIndex可能--多了
// 2.就算arr[1]=334则一开始不需要insertIndex-1
arr[insertIndex + 1] = insertVal;
System.out.println("第"+i+"轮插入:");
System.out.println(Arrays.toString(arr));
}
}
}
优化:
if (insertIndex+1 != i){
arr[insertIndex + 1] = insertVal;
}
例如arr[1]一开始为334 则不需要任何交换排序
时间复杂度
main内
int[] arr = new int[80000];
for (int i = 0; i < 80000; i++) {
arr[i] = (int)(Math.random() * 8000000);//生成[0,8000000)的数
}
Date date1 = new Date();
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String date1Str = simpleDateFormat.format(date1);
System.out.println("排序前的时间是="+date1Str);
//测试冒泡排序
insertSort(arr);
Date date2 = new Date();
String date2Str = simpleDateFormat.format(date2);
System.out.println("排序后的时间是="+date2Str);
希尔排序
插入排序存在的问题-效率低下
希尔排序图解
希尔排序的两种应用方法
交换法
package Sort;
import java.util.Arrays;
public class ShellSort {
public static void main(String[] args) {
int[] arr = {
8,9,1,7,2,3,5,4,6,0};
shellSort1(arr);
}
//使用交换法
public static void shellSort1(int[] arr){
int temp = 0;
int count = 0;
//第1轮
//10个数据分为了5组
for(int gap = arr.length/2;gap > 0;gap /= 2){
for (int i = gap; i < arr.length; i++) {
//遍历各组中所有的元素(共gap组) 步长为gap
for (int j = i-gap; j >= 0 ; j -= gap) {
//如果当前元素大于加上步长后的那个元素 则交换
if (arr[j] > arr[j +gap]){
temp = arr[j];
arr[j] = arr[j+gap];
arr[j+gap] = temp;
}
}
}
System.out.println("希尔排序的第"+(++count)+"轮 = "+ Arrays.toString(arr));
}
}
}
时间复杂度
代码同上
反而比插入排序更慢了
加上弹幕说的break后时间变成了不到1秒,why啊!?谢谢你陌生人(呵呵
答案:减少forj的循环判断
移位法(效率高
//使用交换法
public static void shellSort1(int[] arr){
int temp = 0;
int count = 0;
//第1轮
//10个数据分为了5组
for(int gap = arr.length/2;gap > 0;gap /= 2){
for (int i = gap; i < arr.length; i++) {
//遍历各组中所有的元素(共gap组) 步长为gap
for (int j = i-gap; j >= 0 ; j -= gap) {
//如果当前元素大于加上步长后的那个元素 则交换
if (arr[j] > arr[j +gap]){
temp = arr[j];
arr[j] = arr[j+gap];
arr[j+gap] = temp;
break;
}
}
}
// System.out.println("希尔排序的第"+(++count)+"轮 = "+ Arrays.toString(arr));
}
效率也比方法一高
快速排序
图解
尚学堂老师讲崩了,看了别人的
package Sort;
import java.util.Arrays;
public class QuickSort {
public static void main(String[] args) {
int[] arr = {
-9,78,0,23,-567,70};
//调用方法
quickSort(arr,0,arr.length-1);
System.out.println("排序后:"+Arrays.toString(arr));
}
public static void quickSort(int[] arr,int left,int right){
//进行判断 左下标大于右下标是不合法的
if (left > right){
return;
}
//定义变量保存基准数
int base = arr[left];
//定义变量i 指向左边
int l = left;
//定义变脸j 指向右边
int r = right;
//当i和j不相遇的时候 在循环中检索
while (r != l){
while (arr[r] >= base && l < r){
r--;
}
while (arr[l] <= base && l < r){
l++;
}
//交换
int temp = arr[l];
arr[l] = arr[r];
arr[r] = temp;
}
//如果i和j相遇了 就交换基准数 和 相遇位置元素
//1.吧相遇位置的元素赋值给基准数元素
arr[left] = arr[l];
//吧基准数赋值给相遇位置的元素
arr[l] = base;
//第一轮排序完毕 接下来递归排序所有轮次情况
//排序左边 (从左到相遇位置-1 = 左边
quickSort(arr,left,l-1);
//排序右边
quickSort(arr,r+1,right);
}
}
归并排序
分:
治:
i和j不断后移比较,将比较结果放入有序列中;若i或j一方已经到了最后,则直接将另外一者后面的全部元素加入有序列的最后
思路:
1.先分再治
2.治的原理:
a 先把左右两边(有序)的数据按照规则填充到temp数组
b 把有剩余数据的一边的数据一次全部填充到temp中
c 将temp数组的元素拷贝到arr中
package Sort;
import java.util.Arrays;
public class MergetSort {
public static void main(String[] args) {
int arr[] = {
8,4,5,7,1,3,6,2};
int temp[] = new int[arr.length]; //归并排序需要一个额外空间
mergeSort(arr,0, arr.length- 1,temp);
System.out.println("归并排序后 = "+ Arrays.toString(arr));
}
//分+合方法
public static void mergeSort(int[] arr,int left,int right,int[] temp){
if (left < right){
int mid = (left + right) / 2; //中间索引
//向左递归进行分解
mergeSort(arr, left, mid, temp);
//向右进行分解
mergeSort(arr, mid + 1, right, temp);
//合并
merge(arr,left,mid,right,temp);
}
}
//合并
/**
*
* @param arr 排序的原始数组
* @param left 左边有序序列的初始索引
* @param mid 中间索引
* @param right 右边索引
* @param temp 做中转的数组
*/
public static void merge(int[] arr,int left,int mid,int right,int[] temp) {
System.out.println("XXX");
int i = left; //初始化i 左边有序序列的初始索引
int j = mid + 1; //初始化j 右边有序序列的初始索引
int t = 0; //指向temp数组的当前索引
//一
//先把左右两边(有序)的数据按照规则填充到temp数组
//直到左右两边的有序序列 有一边处理完毕为止
while (i <= mid && j <= right) {
//如果左元素小于等于右元素 则讲左元素填充到temp数组中,并t++ i++
if (arr[i] <= arr[j]) {
temp[t] = arr[i];
t++;
i++;
} else {
//反之
temp[t] = arr[j];
t++;
j++;
}
}
//二
//吧有剩余数据的一边的数据一次全部填充到temp中
while (i <= mid) {
//左序列中有剩余元素 就全部填充到temp中
temp[t] = arr[i];
t++;
i++;
}
while (j <= right) {
//右序列中有剩余元素 就全部填充到temp中
temp[t] = arr[j];
t++;
j++;
}
//三
//讲temp数组的元素拷贝到arr中
//注意不是每次都拷贝所有-只有最后一次才拷贝才能得到正确完整的排序数组
t = 0;
int tempLeft = left;
while (tempLeft <= right){
arr[tempLeft] = temp[t];
t++;
tempLeft++;
}
}
}
基数排序
文字介绍
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VSlCcsW1-1674477290661)(C:\Users\路聃\AppData\Roaming\Typora\typora-user-images\image-20230123163813462.png)]
图文解释 (排序次数 = 数组中最高位数 eg:748最大,则排序3次
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9IbIg5Pq-1674477290662)(C:\Users\路聃\AppData\Roaming\Typora\typora-user-images\image-20230123163836182.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E2iivvIM-1674477290663)(C:\Users\路聃\AppData\Roaming\Typora\typora-user-images\image-20230123163843709.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lYKQae0y-1674477290663)(C:\Users\路聃\AppData\Roaming\Typora\typora-user-images\image-20230123163856407.png)]
代码实现
package Sort;
import java.util.Arrays;
public class RadixSort {
public static void main(String[] args) {
int arr[] = {
53,3,542,748,14,214};
radixSort(arr);
}
//基数排序方法
public static void radixSort(int[] arr){
//定义一个二维数组 表示10个桶 每个桶是一个一维数组
//为防止数据溢出 则每个数组大小为arr.length
//注意:基数排序是空间换时间的经典算法
int[][] bucket = new int[10][arr.length];
//定义一个一维数组
//作用:来记录各个桶中的数据个数
//eg:bucketElementCounts[0] 记录的是bucket[0]桶中数据个数
int[] bucketElementCounts = new int[10];
//第1轮
for (int j = 0; j < arr.length; j++) {
//取出每个元素的个位的值
int digitOfElement = arr[j] % 10;
//放入到对应的桶中 --结合h19和h27就可以看懂
bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
bucketElementCounts[digitOfElement]++;
}
//按照这个通的顺序(一维数组的下标依次取出数据 放入原来数组
int index = 0;
//先遍历每一个桶
for (int k = 0; k < bucketElementCounts.length; k++) {
//如果桶内有数据 我们才放入原数组中
if (bucketElementCounts[k] != 0){
//如果该桶内有数据
//再遍历每一个桶内的数据
for (int l = 0; l < bucketElementCounts[k]; l++) {
//取出元素放入arr
arr[index++] = bucket[k][l];
}
}
//给每个桶的记录数组清零
bucketElementCounts[k] = 0;
}
System.out.println("第1轮 对个位的排序处理是 arr = "+ Arrays.toString(arr));
//第2轮
for (int j = 0; j < arr.length; j++) {
//取出每个元素的个位的值
int digitOfElement = arr[j] / 10 % 10;
//放入到对应的桶中 --结合h19和h27就可以看懂
bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
bucketElementCounts[digitOfElement]++;
}
//按照这个通的顺序(一维数组的下标依次取出数据 放入原来数组
index = 0;
//先遍历每一个桶
for (int k = 0; k < bucketElementCounts.length; k++) {
//如果桶内有数据 我们才放入原数组中
if (bucketElementCounts[k] != 0){
//如果该桶内有数据
//再遍历每一个桶内的数据
for (int l = 0; l < bucketElementCounts[k]; l++) {
//取出元素放入arr
arr[index++] = bucket[k][l];
}
}
//给每个桶的记录数组清零
bucketElementCounts[k] = 0;
}
System.out.println("第2轮 对十位的排序处理是 arr = "+ Arrays.toString(arr));
//第3轮
for (int j = 0; j < arr.length; j++) {
//取出每个元素的个位的值
int digitOfElement = arr[j] /100 % 10;
//放入到对应的桶中 --结合h19和h27就可以看懂
bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
bucketElementCounts[digitOfElement]++;
}
//按照这个通的顺序(一维数组的下标依次取出数据 放入原来数组
index = 0;
//先遍历每一个桶
for (int k = 0; k < bucketElementCounts.length; k++) {
//如果桶内有数据 我们才放入原数组中
if (bucketElementCounts[k] != 0){
//如果该桶内有数据
//再遍历每一个桶内的数据
for (int l = 0; l < bucketElementCounts[k]; l++) {
//取出元素放入arr
arr[index++] = bucket[k][l];
}
}
//给每个桶的记录数组清零
bucketElementCounts[k] = 0;
}
System.out.println("第3轮 对百位的排序处理是 arr = "+ Arrays.toString(arr));
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6nOVgnAu-1674477290664)(C:\Users\路聃\AppData\Roaming\Typora\typora-user-images\image-20230123185219517.png)]
代码简化
···
public static void radixSort(int[] arr){
//得到数组中最大的数的位数
//1.获取最大的数
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max){
max = arr[i];
}
}
//2.得到最大数的位数
int maxLength = (max + "").length();
//定义一个二维数组 表示10个桶 每个桶是一个一维数组
//为防止数据溢出 则每个数组大小为arr.length
//注意:基数排序是空间换时间的经典算法
int[][] bucket = new int[10][arr.length];
//定义一个一维数组
//作用:来记录各个桶中的数据个数
//eg:bucketElementCounts[0] 记录的是bucket[0]桶中数据个数
int[] bucketElementCounts = new int[10];
//简化代码
//第i轮
for (int i = 0,n = 1; i < maxLength; i++,n*=10) {
//第1轮
for (int j = 0; j < arr.length; j++) {
//取出每个元素的个位的值
int digitOfElement = arr[j] / n % 10;
//放入到对应的桶中 --结合h19和h27就可以看懂
bucket[digitOfElement][bucketElementCounts[digitOfElement]] = arr[j];
bucketElementCounts[digitOfElement]++;
}
//按照这个通的顺序(一维数组的下标依次取出数据 放入原来数组
int index = 0;
//先遍历每一个桶
for (int k = 0; k < bucketElementCounts.length; k++) {
//如果桶内有数据 我们才放入原数组中
if (bucketElementCounts[k] != 0){
//如果该桶内有数据
//再遍历每一个桶内的数据
for (int l = 0; l < bucketElementCounts[k]; l++) {
//取出元素放入arr
arr[index++] = bucket[k][l];
}
}
//给每个桶的记录数组清零
bucketElementCounts[k] = 0;
}
System.out.println("第"+(i+1)+"轮 对倒数第"+(i+1)+"位的排序处理是 arr = "+ Arrays.toString(arr));
}
}
排序算法时间复杂度比较
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eLibRiHB-1674477290664)(C:\Users\路聃\AppData\Roaming\Typora\typora-user-images\image-20230123191324545.png)]
计数排序、桶排序待学习
相关术语补充
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jgwdV6kD-1674477290664)(C:\Users\路聃\AppData\Roaming\Typora\typora-user-images\image-20230123191407632.png)]
其他:
全排列
所有排列的可能,例如:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xme3NlOc-1674477290664)(C:\Users\路聃\AppData\Roaming\Typora\typora-user-images\image-20230123192350824.png)]
各个排序的区别总结
冒泡:像气泡一样从左到右相邻元素依次交换,大气泡被抬到最后
选择:从无序列中,不断选取最小值,加入到有序列中
插入:从无序列中,从左到右不断将数插入进有序列中
----------------------------在次数多时,效率低下
希尔:不断/2分组的对应交叉组,对每次分好组后进行交换法/移位法
快速:(累)
归并:先拆分后合并
基数:位数=排序次数,从个位开始,按位数不断排序
刷题
老子的全排列呢
A-老子的全排列呢_牛客竞赛语法入门班数组栈、队列和stl习题 (nowcoder.com)
难题啊www…还是适合中午刷题,困。。
解决方法:
- [DFS]((555条消息) 牛客 老子的全排列呢 (DFS)_四维2000的博客-CSDN博客)
- C中STL函数 老子的全排列呢_水蛙菌的博客-CSDN博客](https://blog.csdn.net/qq_44826711/article/details/114002029?ops_request_misc=%7B%22request%5Fid%22%3A%22167447685416782427427006%22%2C%22scm%22%3A%2220140713.130102334.pc%5Fall.%22%7D&request_id=167447685416782427427006&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_ecpm_v1~hot_rank-2-114002029-null-null.142v71pc_search_v2,201v4add_ask&utm_term=老子的全排列呢 &spm=1018.2226.3001.4187)