1.给定一个数组arr,和一个数num,请把小于等于num的数放在数组的左边,大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)
/** * 给定一个数组arr,和一个数num,请把小于等于num的数放在数组的左边, * 大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N) */ @Slf4j public class Alg008_SeparateArr { @Test public void test(){ for(int i=0;i<5000;i++){ int[] arr = generateArr(); int[] vals = separate(arr, 0); log.info("vals:{}", vals); } } private int[] separate(int[] arr, int target){ if(arr.length <2){ return arr ; } int l =0; for(int i=0;i<arr.length;i++){ if(arr[i] < target){ swap(arr,l++,i); } } return arr; } public static void swap(int[] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } private int[] generateArr(){ return new Random().ints(-100, 100).distinct().limit(20).toArray(); } }
解题思路: 借助一个辅助变量L下标为0, 遍历数组 比较小于sum的值,与L交换,同时L++
2.(荷兰国旗问题)给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间,大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N)
/** * 给定一个数组arr,和一个数num,请把小于num的数放在数组的左边,等于num的数放在数组的中间, * 大于num的数放在数组的右边。要求额外空间复杂度O(1),时间复杂度O(N) */ @Slf4j public class Alg009_NetherlandsFlag { @Test public void test(){ for(int i=0;i<5000;i++){ int[] arr = generateArr(); log.info("result:{}", change(arr, 0, arr.length-1, 0)); } } // push the L close to R public int[] change(int[] arr, int L,int R,int target){ int l = L-1; int r = R+1; while(L < r){ if(arr[L] < target){ swap(arr,++l,L++); } else if(arr[L] > target){ swap(arr, --r,L); } else { L++; } } return arr; } public static void swap(int[] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } private int[] generateArr(){ return new Random().ints(-100, 100).distinct().limit(20).toArray(); } }
解题思路: 给数组规定左边界和右边界,以及移动的指针i, 一共有三种比较
1. arr[i] < num, i和左边界的下一位交换,同时左边界右扩一位,i++
2. arr[i] == num, i++
3. arr[i] > num, i和右边界的前一位交换,同时右边界左扩一位,i原地不动