《劍指offer》算法題第八天
阿新 • • 發佈:2018-02-04
off target 最大 問題 得到 return part 快排 連續子數組
今日題目(對應書上第39~42題):
- 數組中出現次數超過一半的數字
- 最小的k個數(top k,重點!)
- 數據流中的中位數
- 連續子數組的最大和
今天的題目都比較經典,特別是第2題。
1. 數組中出現次數超過一半的數字
題目描述: 數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度為9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2。如果不存在則輸出0。
思路:
有兩種方法,
一,利用類似於快排的思想,尋找數組中的中位數,然後再檢查是否滿足出現次數。
二,根據數組的特點來做。
代碼如下:
1 //方法一,快排 2public class Solution { 3 public int MoreThanHalfNum_Solution(int [] array) { 4 if(array.length == 0) return 0; 5 int start = 0, end = array.length-1; 6 int mid = array.length>>1; 7 while(start < end){ 8 int ind = partition(array,start,end);9 if(ind == mid) 10 break; 11 if(ind > mid) 12 end = ind-1; 13 if(ind < mid) 14 start = ind+1; 15 } 16 if(check(array,array[mid])) 17 return array[mid]; 18 else return 0; 19 }20 21 public boolean check(int[] nums,int result){ 22 int times = 0; 23 for(int n:nums){ 24 if(n == result) 25 times++; 26 } 27 return times*2 > nums.length; 28 } 29 30 public int partition(int[] nums,int start,int end){ 31 int target = nums[end]; 32 int res = start; 33 for(int i = start; i < end; i++){ 34 if(nums[i] < target){ 35 int swap = nums[i]; 36 nums[i] = nums[res]; 37 nums[res] = swap; 38 res++; 39 } 40 } 41 nums[end] = nums[res]; 42 nums[res] = target; 43 return res; 44 } 45 } 46 47 48 //方法二 49 public int MoreThanHalfNum_Solution(int [] array) { 50 if(array.length == 0) return 0; 51 int result = array[0]; 52 int times = 1; 53 for(int n:array){ 54 if(times == 0){ 55 result = n; 56 times = 1; 57 }else if(result == n) 58 times++; 59 else 60 times--; 61 } 62 if(check(array,result)) 63 return result; 64 else return 0; 65 }
2. 最小的k個數
題目描述: 輸入n個整數,找出其中最小的K個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4,。
思路:
這道題是經典的top K問題,有兩種解法:
1,運用快排,找出第K個數的位置,將前面的數輸出
2,利用容量為K的最大堆,循環數組,每次替換掉堆中最大的數
代碼如下:
1 //快排 2 public class Solution { 3 public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) { 4 ArrayList<Integer> res = new ArrayList(); 5 if(k > input.length || k == 0) return res; 6 int start = 0, end = input.length-1; 7 int ind = partition(input,start,end); 8 while(ind != k-1){ 9 if(ind > k-1){ 10 end = ind-1; 11 }else{ 12 start = ind+1; 13 } 14 ind = partition(input,start,end); 15 } 16 for(int i = 0;i < k; i++) 17 res.add(input[i]); 18 return res; 19 } 20 21 public int partition(int[] nums,int start,int end){ 22 int target = nums[end]; 23 int ind = start; 24 for(int i = start; i < end;i++){ 25 if(nums[i] < target){ 26 int swap = nums[i]; 27 nums[i] = nums[ind]; 28 nums[ind] = swap; 29 ind++; 30 } 31 } 32 nums[end] = nums[ind]; 33 nums[ind] = target; 34 return ind; 35 } 36 } 37 38 39 //利用最大堆 40 public class Solution { 41 public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) { 42 if(k > input.length || k < 1) return new ArrayList(); 43 PriorityQueue<Integer> maxHeap = new PriorityQueue(k,new Comparator<Integer>(){ 44 public int compare(Integer o1,Integer o2){ 45 return o2.compareTo(o1); 46 } 47 }); 48 for(int i = 0; i < input.length; i++){ 49 if(maxHeap.size() < k) 50 maxHeap.add(input[i]); 51 else{ 52 if(maxHeap.peek() > input[i]){ 53 maxHeap.poll(); 54 maxHeap.add(input[i]); 55 } 56 } 57 } 58 return new ArrayList(maxHeap); 59 } 60 }
3.數據流中的中位數
題目描述:
如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那麽中位數就是所有數值排序之後位於中間的數值。如果從數據流中讀出偶數個數值,那麽中位數就是所有數值排序之後中間兩個數的平均值。
思路:
這道題的關鍵是選擇一個怎樣的數據結構來維護數據流,可以使插入和查詢的速度都比較理想。在這邊維護了一個最大堆和一個最小堆,最大堆存儲中位數左邊的數字,最小堆存儲中位數右邊的數字。
代碼如下:
1 public class Solution { 2 int count = 0; 3 PriorityQueue<Integer> min = new PriorityQueue(); 4 PriorityQueue<Integer> max = new PriorityQueue(new Comparator<Integer>(){ 5 public int compare(Integer o1,Integer o2){ 6 return o2-o1; 7 } 8 }); 9 public void Insert(Integer num) { 10 if((count&1) == 0){ 11 min.offer(num); 12 max.offer(min.poll()); 13 }else{ 14 max.offer(num); 15 min.offer(max.poll()); 16 } 17 count++; 18 } 19 20 public Double GetMedian() { 21 if(((min.size()+max.size())&1) == 0) 22 return (min.peek()+max.peek())/2.0; 23 else 24 return max.peek()*1.0; 25 } 26 }
4.連續子數組的最大和
題目描述:
輸入一個整數數組,數組裏有正數也有負數。數組中的一個或連續多個整數組成一個子數組。求所有子數組的和的最大值。要求時間復雜度為O(n)。
思路:
這道題也算是比較經典的一道題了,面經裏面經常看到,下面給出兩種解法。
代碼如下:
1 //解法一 2 public class Solution { 3 public int FindGreatestSumOfSubArray(int[] array) { 4 int max = Integer.MIN_VALUE; 5 int sum = 0; 6 for(int n:array){ 7 if(sum <= 0) 8 sum = n; 9 else 10 sum += n; 11 max = max>sum?max:sum; 12 13 } 14 return max; 15 } 16 } 17 18 19 //解法二,動態規劃 20 public class Solution { 21 public int FindGreatestSumOfSubArray(int[] array) { 22 int[] dp = new int[array.length]; 23 dp[0] = array[0]; 24 for(int i = 1; i < array.length; i++){ 25 if(dp[i-1] < 0) 26 dp[i] = array[i]; 27 else 28 dp[i] = array[i] + dp[i-1]; 29 } 30 int res = dp[0]; 31 for(int n:dp) 32 res = n>res?n:res; 33 return res; 34 } 35 }
《劍指offer》算法題第八天