《剑指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 }

原文地址:https://www.cnblogs.com/wezheng/p/8413800.html

时间: 2024-10-27 23:46:03

《剑指offer》算法题第八天的相关文章

剑指offer算法总结

剑指offer算法学习总结 节选剑指offer比较经典和巧妙的一些题目,以便复习使用.一部分题目给出了完整代码,一部分题目比较简单直接给出思路.但是不保证我说的思路都是正确的,个人对算法也不是特别在行,只不过这本书的算法多看了几遍多做了几遍多了点心得体会.于是想总结一下.如果有错误也希望能指出,谢谢. 具体代码可以参考我的GitHub仓库: https://github.com/h2pl/SwordToOffer 数论和数字规律 从1到n整数中1出现的次数 题目描述 求出1~13的整数中1出现的

剑指 offer 第一题: 二维数组中的查找

打算写 图解剑指 offer 66 题 的系列文章,不知道大家有没有兴趣 ?? 题目描述 在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 题目分析 图 1 如果没有头绪的话,很显然使用 暴力解法 是完全可以解决该问题的. 即遍历二维数组中的每一个元素,时间复杂度:O(n^2). 其实到这里我们就可以发现,使用这种暴力解法并没有充分利用题目给出的信息.这

剑指offer链表题的双指针法总结

本篇博客旨在总结双指针法在剑指offer链表题中的应用 包括删除链表中重复的节点.链表中倒数第k个节点.链表中环的入口节点.反转链表.合并两个排序的链表.两个链表的第一个公共节点. 根据双指针的类型,可以大致分为三种: 第一种是间隔一定距离的双指针法,包括删除链表中重复的节点.链表中倒数第k个节点两题 删除链表中重复的节点 在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针. 例如,链表1->2->3->3->4->4->5

剑指offer编程题Java实现——面试题12相关题大数的加法、减法、乘法问题的实现

用字符串或者数组表示大数是一种很简单有效的表示方式.在打印1到最大的n为数的问题上采用的是使用数组表示大数的方式.在相关题实现任意两个整数的加法.减法.乘法的实现中,采用字符串对大数进行表示,不过在具体的计算中,还是要将字符串转化成字符数组来进行计算. 实现两个大数的加法,要考虑到两个问题,两个数的和的位数问题,以及如何处理两个数按位相加产生的进位问题.首先两个整数相加,两个数的和的位数最多比最大的整数的位数多1:这样和的位数就确定了.对于进位问题,我的做法是先进行按位相加,相加操作完成后再按照

剑指offer编程题Java实现——面试题9斐波那契数列

题目:写一个函数,输入n,求斐波那契数列的第n项. 1 package Solution; 2 3 /** 4 * 剑指offer面试题9:斐波那契数列 5 * 题目:写一个函数,输入n,求斐波那契数列的第n项. 6 * 0, n=1 7 * 斐波那契数列定义如下:f(n)= 1, n=2 8 * f(n-1)+f(n-2), n>2 9 * @author GL 10 * 11 */ 12 public class No9Fibonacci { 13 14 public static void

剑指offer编程题Java实现——面试题7相关题用两个队列实现一个栈

剑指offer面试题7相关题目:用两个队列实现一个栈 解题思路:根据栈的先入后出和队列的先入先出的特点1.在push的时候,把元素向非空的队列内添加2.在pop的时候,把不为空的队列中的size()-1份元素poll出来,添加到另为一个为空的队列中,再把队列中最后的元素poll出来两个队列在栈不为空的情况下始终是有一个为空,另一个不为空的.push添加元素到非空的队列中,pop把非空队列的元素转移到另一个空的队列中,直到剩下最后一个元素,这个元素就是要出栈的元素(最后添加到队列中的元素). 1

剑指offer编程题Java实现——面试题14调整数组顺序使奇数位于偶数之前

题目: 输入一个整数数组,实现一个函数来调整该数组中数组的顺序,使得所有的奇数位于数组的前半部分,偶数位于数组的后半部分. 解题思路:数组中维护两个指针,第一个指针初始化时候指向数组头部,第二个指针初始化时候指向数组尾部,第一个指针指向的数字总是偶数,第二个指针指向的数字总是奇数,如果第一个指针在第二个指针之前,则交换两指针指向的元素. 1 package Solution; 2 3 /** 4 * 剑指offer面试题14:调整数组顺序是奇数位于偶数前面 5 * 题目:输入一个整数数组,实现一

剑指offer编程题Java实现——面试题10二进制中1的个数

题目: 请实现一个函数,输入一个整数,输出该整数二进制表示中1的个数.例如,把9表示成二进制是1001,有2位是1,该函数输出2解法:把整数减一和原来的数做与运算,会把该整数二进制表示中的最低位的1变成0,与运算进行多少次就有多少个1. 1 package Solution; 2 /** 3 * 剑指offer面试题10:二进制中1的个数 4 * 题目:请实现一个函数,输入一个整数,输出该整数二进制表示中1的个数. 5 * 例如,把9表示成二进制是1001,有2位是1,该函数输出2 6 * 解法

剑指offer刷题—二维数组的查找

最近接触到一本书叫做剑指offer,在这里准备在这个2个月左右将这本书刷完,当然,不需要每天多少道什么的,不在多,一天理解一道就好了,希望能成为一种习惯,另外,准备在github上也进行同步分享. 今天第一道题: 面试题3:二位数组中的查找 当我们需要解决一个复杂问题时,一个很有效的方法就是从具体的问题出手,通过分析具体的例子,得到规律. 再一个二维数组中,每一行都要按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排列.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含

剑指offer刷题记录

[TOC] 二维数组中的查找 在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序.请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数. 解题思路:从右上角的元素进行判断,如果大于target说明这一列肯定都不是,所以将列数见一:如果小于target说明可能在下一行是等于target的,所以这一行都不是解,所以将行数加1.这样通过一个循环进行判断即可. class Solution { public: bool Find(int tar