1. 给定一个数组和一个数num,将比num小的数放在数组的左边,大的数放右边。
要求额外空间复杂度为O(1),时间复杂符为O(N) 即只借助有限个变量,只进行一次常数次操作
1.1 借助一个变量x,此变量指向数组的最前面-1,0~x表示小于等于num的范围
1.2 判断这个数比num大还是小,如果大的话保持不变,如果小的话,与索引为x+1的数进行交换
1.3 并且x+1扩大范围
1.4 代码:
int[] arr = {1,2,6,7,2,4};
int num = 3;
int x = -1;
for(int i=0;i<arr.length;i++){
if(arr[i]<num){
int temp = arr[x+1];
arr[++x] = arr[i];
arr[i] = temp;
}
}
2. 荷兰国旗问题
给定一个数组arr, 和一个数num, 请把小于num的数放在数组的左边, 等于num的数放在数组的中间, 大于num的数放在数组的右边。 要求额外空间复杂度O(1), 时间复杂度O(N)
2.1 与之前那道题类似,不过本题需要多写一个变量y=N,y~N-1表示大于num的数的范围
2.2 从左边开始,如果小,则当前数与x+1位置的数进行交换;x再加1,当前数+1
如果等于则保持不变;当前数+1
如果大,则当前数与y-1位置的数进行交换;y再加1,当前数保持不变
2.3 代码:
int[] arr = {1,2,6,3,7,2,4};
int num = 3;
int x = -1;
int y = arr.length;
for(int i=0;i<y;i++){
if(arr[i]<num){
int temp = arr[x+1];
arr[++x] = arr[i];
arr[i] = temp;
}
else if(arr[i]>num){
int temp = arr[y-1];
arr[--y] = arr[i];
arr[i] = temp;
i--;
}
}
3. 随机快速排序 O(NlogN) 额外空间复杂度O(logN)
3.1 以第一个数为基准,将数组分为小于第一个数的数组,大于第一个的数组,中间的为等于第一个数的数组
3.2 再将分别以数第一个为基准,循环
3.3 代码:
public static void quickSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
quickSort(arr, 0, arr.length - 1);
}
public static void quickSort(int[] arr, int l, int r) {
if (l < r) {
swap(arr, l + (int) (Math.random() * (r - l + 1)), r);
int[] p = partition(arr, l, r);
quickSort(arr, l, p[0] - 1);
quickSort(arr, p[1] + 1, r);
}
}
public static int[] partition(int[] arr, int l, int r) {
int less = l - 1;
int more = r;
while (l < more) {
if (arr[l] < arr[r]) {
swap(arr, ++less, l++);
} else if (arr[l] > arr[r]) {
swap(arr, --more, l);
} else {
l++;
}
}
swap(arr, more, r);
return new int[] { less + 1, more };
}
public static void swap(int[] arr, int i, int j) {
int tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
3. 堆是一颗完全二叉树。包括满二叉树(任何一个非叶节点(叶节点表示二叉树的最终节点,即最后一排的节点)都是有左边和右边的)和完全二叉树(前面的是满二叉树,最后一排从左往右依次补齐) 如下图,左边是完全二叉树,右边是满二叉树。
2.1数组可以变为一颗完全二叉树
任意一个下标i,该节点的左边是2*i+1,右边是2*i+2,父节点是(i-1)/2 除法为地板除,只保留整数位
2.2 大根堆
任意一个树的根都是最大的。如整个树的根是最大的,其中的子树中,根也是最大的。
2.3 小根堆
任意一个树的根都是最小的。如整个树的根是最小的,其中的子树中,根也是最小的。
2.4 堆排序 (将数组从小到大排序)
2.4.1 先把数组变成大根堆,然后将数组的最后一个元素与第一个元素交换,此时最后一个元素即为最大元素
2.4.2 再将除了最后一个元素的数组进入大根堆进行下沉,循环
2.4.3 代码:
public static void heapSort(int[] arr){
if(arr==null|arr.length<2){
return;
}
for(int i=0;i<arr.length;i++){ //先进行大根堆排序
heapInsert(arr,i);
}
int size = arr.length;
swap(arr,0,--size);
while(size>0){
heapInfer(arr,0,size); //调整第一个元素在大根堆的位置
swap(arr,0,--size); //数组中最后一个元素与第一个元素交换
}
}
public static void heapInfer(int[] arr,int index,int size){
int left = 2*index + 1;
int right = left + 1;
int largest=0;
while(left<size){ //要满足只要有左节点
if(right<size){ //如果有右节点,那么找出左右最大的,再和根节点对比
largest = arr[right]>arr[left]?right:left;
largest = arr[largest]>arr[index]?largest:index;
}
else{largest = arr[left]>arr[index]?left:index;}//没有的话,只用左节点与根对比
if(largest==index){break;}
swap(arr,index,largest); //交换
index = largest; //继续下沉
left = index*2 + 1;
}
}
public static void heapInsert(int[] arr,int index){
while(arr[index]>arr[(index-1)/2]){
int temp = arr[index];
arr[index] = arr[(index-1)/2];
arr[(index-1)/2] = temp;
index = (index-1)/2;
}
}