Find median
O(n) look for the median(or any target rank) in an array
1 class Solution { 2 public static void main(String[] args) { 3 Solution solution = new Solution(); 4 solution.findMedian(new int[]{4, 1, 9}); 5 solution.findMedian(new int[]{4, 1, 9, 3}); 6 solution.findMedian(new int[]{4, 1, 9, 3, 0, 6, 1, 6, 4}); 7 solution.findMedian(new int[]{-1, 4, 1, 9, 3, 0, 6, 1, 6, 4}); 8 solution.findMedian(new int[]{4, 1, 9, 3, 0, 6, 1, 6, 4, 2, 3}); 9 solution.findMedian(new int[]{4, -10, -22, 1, 9, 3, 0, 6, 1, 6, 4, 2, 3}); 10 solution.findMedian(new int[]{4, 1, 9, 3, 0, 6, 12, 13, 1, 6, 4, 10, 2, 3}); 11 } 12 13 void findMedian(int[] arr) { 14 if (arr.length % 2 == 1) { 15 int found = findSingleTarget(arr, 0, arr.length - 1, arr.length / 2); 16 System.out.println(String.format("Rank (%d) found using findSingleTarget algorithm: %d", arr.length / 2, found)); 17 } else { 18 int found1 = findSingleTarget(arr, 0, arr.length - 1, (arr.length - 1) / 2); 19 // We don't need to look for twice, should be optimizable. 20 int found2 = findSingleTarget(arr, 0, arr.length - 1, arr.length / 2); 21 System.out 22 .println(String.format("Rank (%d, %d) found using findSingleTarget algorithm: %s", (arr.length - 1) / 2, 23 arr.length / 2, (found1 + found2) / 2.0)); 24 } 25 26 Arrays.sort(arr); 27 System.out.println(String 28 .format("Sorted array: %s Total count: %d, number in the middle(%d): %d", Arrays.toString(arr), arr.length, 29 arr.length / 2, arr[arr.length / 2])); 30 System.out.println(); 31 } 32 33 /** 34 * @param target is the rank(index) of a value, which we are looking for, if this arr is sorted 35 */ 36 int findSingleTarget(int[] arr, int leftInclusive, int rightInclusive, int target) { 37 if (leftInclusive > rightInclusive) { 38 throw new IllegalArgumentException(); 39 } 40 if (leftInclusive == rightInclusive) { 41 if (leftInclusive == target) { 42 return arr[leftInclusive]; 43 } 44 throw new IllegalArgumentException(); 45 } 46 47 int left = leftInclusive; 48 int right = rightInclusive; 49 50 int pivot = arr[left]; //use the first element as the pivot 51 ++left; 52 53 while (left <= right) { 54 int current = arr[left]; 55 if (current <= pivot) { 56 //lazy "swap" pivot with left 57 arr[left - 1] = arr[left]; 58 ++left; 59 } else { 60 //swap left and right 61 swap(arr, left, right); 62 --right; 63 } 64 } 65 int pivotIndex = left - 1; 66 arr[left - 1] = pivot; 67 if (pivotIndex == target) { 68 return pivot; 69 } 70 71 if (pivotIndex < target) { 72 return findSingleTarget(arr, pivotIndex + 1, rightInclusive, target); 73 } 74 75 return findSingleTarget(arr, leftInclusive, pivotIndex - 1, target); 76 } 77 78 private void swap(int[] array, int a, int b) { 79 int tmp = array[a]; 80 array[a] = array[b]; 81 array[b] = tmp; 82 } 83 }
A similar idea can be used to partition an array into two subarrays where values from one array are strictly less than values from another array.
1 class Solution { 2 public static void main(String[] args) { 3 Solution solution = new Solution(); 4 System.out.println(solution.canPartition(new int[]{11, 6, 5, 1, 2, 4, 3})); 5 System.out.println(solution.canPartition(new int[]{1, 1, 1, 1, 1, 3})); 6 System.out.println(solution.canPartition(new int[]{4, 1, 2, 3})); 7 System.out.println(solution.canPartition(new int[]{1, 2, 3, 4})); 8 System.out.println(solution.canPartition(new int[]{1, 5, 7, 1})); 9 System.out.println(solution.canPartition(new int[]{12, 7, 6, 7, 6})); 10 System.out.println(solution.canPartition(new int[]{5, 1, 2, 3, 5})); 11 } 12 13 boolean canPartition(int[] arr) { 14 int sum = 0; 15 for (int num : arr) { 16 sum += num; 17 } 18 19 if (sum % 2 != 0) { 20 return false; 21 } 22 23 //return canPartitionInPlace(arr, 0, arr.length - 1, 0, sum / 2); 24 return canPartition(arr, 0, sum / 2); 25 } 26 27 /** 28 * An in-place solution for partition the array. 29 */ 30 boolean canPartitionInPlace(int[] arr, int leftInclusive, int rightInclusive, int runningSum, int target) { 31 if (leftInclusive > rightInclusive) { 32 return false; 33 } 34 if (leftInclusive == rightInclusive) { 35 return runningSum + arr[leftInclusive] == target; 36 } 37 38 int newSum = runningSum; 39 int pivot = arr[rightInclusive]; 40 int boundary = leftInclusive; //all values to the left of boundary are <= pivot 41 42 for (int i = leftInclusive; i < rightInclusive; ++i) { 43 if (arr[i] <= pivot) { 44 newSum += arr[i]; 45 swap(arr, boundary++, i); 46 } 47 } 48 49 //include the pivot to the left section 50 swap(arr, boundary, rightInclusive); 51 newSum += arr[boundary]; 52 53 if (newSum < target) { 54 // boundary + 1 will point to a different value 55 return canPartitionInPlace(arr, boundary + 1, rightInclusive, newSum, target); 56 } 57 58 if (newSum > target) { 59 //the pivot should fall into right section in next iteration. So moving boundary left. 60 while (boundary >= leftInclusive && arr[boundary] == pivot) { 61 --boundary; 62 } 63 64 if (boundary <= leftInclusive) { 65 return false; 66 } 67 //restart the process using last runningSum using the left section 68 return canPartitionInPlace(arr, leftInclusive, boundary, runningSum, target); 69 } 70 71 return true; 72 } 73 74 /** 75 * A solution with auxiliary data structure 76 */ 77 boolean canPartition(int[] arr, int runningSum, int target) { 78 if (arr.length == 0) { 79 return false; 80 } 81 82 int sumWithPivot = 0; 83 int pivot = arr[0]; 84 List<Integer> lowerSection = new ArrayList<>(); 85 List<Integer> higherSection = new ArrayList<>(); 86 for (int num : arr) { 87 if (num < pivot) { 88 sumWithPivot += num; 89 lowerSection.add(num); 90 } else if (num == pivot) { 91 sumWithPivot += num; 92 } else { 93 higherSection.add(num); 94 } 95 } 96 97 int newSum = runningSum + sumWithPivot; 98 if (newSum == target) { 99 return true; 100 } else if (newSum < target) { 101 int[] rightArray = new int[higherSection.size()]; 102 for (int i = 0; i < higherSection.size(); ++i) { 103 rightArray[i] = higherSection.get(i); 104 } 105 return canPartition(rightArray, newSum, target); 106 } else { 107 int[] leftArray = new int[lowerSection.size()]; 108 for (int i = 0; i < lowerSection.size(); ++i) { 109 leftArray[i] = lowerSection.get(i); 110 } 111 return canPartition(leftArray, runningSum, target); 112 } 113 } 114 115 void swap(int[] arr, int a, int b) { 116 if (a == b) { 117 return; 118 } 119 120 int t = arr[a]; 121 arr[a] = arr[b]; 122 arr[b] = t; 123 } 124 }
* A similar question in leetcode but without constraints on two sub-arrays: https://leetcode.com/problems/partition-equal-subset-sum/