1. 程式人生 > >《劍指offer》算法題第八天

《劍指offer》算法題第八天

off target 最大 問題 得到 return part 快排 連續子數組

今日題目(對應書上第39~42題):

  1. 數組中出現次數超過一半的數字
  2. 最小的k個數(top k,重點!)
  3. 數據流中的中位數
  4. 連續子數組的最大和

今天的題目都比較經典,特別是第2題。

1. 數組中出現次數超過一半的數字

題目描述:
數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度為9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2。如果不存在則輸出0。

思路:
有兩種方法,
一,利用類似於快排的思想,尋找數組中的中位數,然後再檢查是否滿足出現次數。
二,根據數組的特點來做。

代碼如下:

 1 //方法一,快排
 2
public 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》算法題第八天