zoukankan      html  css  js  c++  java
  • 《剑指offer》算法题第八天

    今日题目(对应书上第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 }
  • 相关阅读:
    Celery详解
    JWT详解
    进程及进程池
    多线程详解
    python常用模块之os模块的用法
    python常用模块之paramiko与ssh
    reflect 反射
    http 静态文件
    模板渲染语言
    http web 开发
  • 原文地址:https://www.cnblogs.com/wezheng/p/8413800.html
Copyright © 2011-2022 走看看