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/

 

posted @ 2021-01-12 03:22  新一代的天皇巨星  阅读(109)  评论(0编辑  收藏  举报