文章内容为LeetCode刷题笔记,如发现错误请多多指教
23、数组中出现次数超过一半的数字:数组使用,简单算法的设计
数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
这个题是比较简单的,可以有三种思路:
1、定义map,使用<数字,次数>的映射关系,最后统计每个字符出现的次数。
2、将数组排序,那么超过数组大小一半的数字肯定在数组中间位置,然后统计该数字的次数是否符合要求
3、目标条件:目标数据超过数组长度的一半,那么对数组,我们同事去掉两个不同的数字,到最后剩下的一个数就是该数字,如果剩下两个,那么这两个也是一样的,就是结果,在其基础上把最后剩下的一个数字或者两个返回到原来数组中,遍历数组检查该数字出现的次数进行最终判断。
//思路一:使用hash表
class Solution {
public:
int majorityElement(vector<int>& nums) {
unordered_map<int,int> map;
int half=nums.size()/2;
for(int i=0;i<nums.size();i++){
auto it=map.find(nums[i]);
//如果找到了,那么就进行自增,如果不在那么就是首次出现,插入
if(it!=map.end()){
map[nums[i]]++;
}
else map.insert(make_pair(nums[i],1));
//走到这里说明对应的key值一定存在,进行判定
if(map[nums[i]]>half){
return nums[i];
}
}
return 0;
}
};
//思路二,排序方式
class Solution {
public:
int majorityElement(vector<int>& nums) {
int size=nums.size();
int count=0;
sort(nums.begin(),nums.end());
for(int i=0;i<size;i++){
if(nums[i]==nums[size/2]){
count++;
}
}
if(count>(size/2)){
return nums[size/2];
}
return 0;
}
};
//思路三:不同数字抵消方式求解
class Solution {
public:
int majorityElement(vector<int>& nums) {
if(nums.size()<0) return 0;
int time =1;//time决定了当前number可以抵消几次不同数字
int number=nums[0];
for(int i=1;i<nums.size();i++){
//当time等于0的时候,说明两个数字不同且都抵消了
if(time==0){
number=nums[i];
time=1;
}
//如果相同就让当前number与后面数字多抵消一次
else if(nums[i]==number){
time++;
}
else{
time--;
}
}
//到这一步,number就是我们要找的数字,但是还需要验证一下他出现的次数是否符合条件
int count=0;
for(int i=0;i<nums.size();i++){
if(nums[i]==number){
count++;
}
}
return count>nums.size()/2 ? number:0;
}
};
24、最小的K个数:topK问题
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
这个问题有多种思路,首先可以先排序,然后输出k个数,但是这个可能会比较慢,我们可以选择最大堆的方法来解决这个问题,具体思路是:首先建立一个最大堆,采用优先队列的容器来实现这个最大堆,那么我们先输入k个数,这k个数会在堆里降序排列(因为最大堆根节点是最大的嘛),当再有数来时,让它和队头进行比较,如果比队头的元素值小,那么pop(队头),push(该值),遍历一遍数组,就完成了对比arr[k]值大的元素的提出,剩下的就是前topK个元素
struct comp{
bool operator()(const int &a,const int &b){
return a<b;//我们需要最大堆,所以选择降序排序
}
};
class Solution {
public:
vector<int> getLeastNumbers(vector<int>& arr, int k) {
vector<int> list;
if(arr.size()==0||k<=0||k>arr.size()){
return list;
}
priority_queue<int,vector<int>,comp> queue;//采用容器优先级队列实现最大堆
for(int i=0;i<arr.size();i++){
if(i<k){
queue.push(arr[i]);
}
else{
if(arr[i]<queue.top()){
queue.pop();
queue.push(arr[i]);
}
}
}
for(int i=0;i<k;i++){
list.push_back(queue.top());
queue.pop();
}
return list;
}
};
25、连续数组的最大和:简单动规问题
输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。
要求时间复杂度为O(n)。
这个题我们可以用动规的方法来解决,让输入的数组每个值为以这个值结尾的连续数组的最大值,举个例子,就拿上面的数组来说,nums[1]=1,转换完成之后nums[1]还为1,因为以nums[1]结尾的最大连续数组值为一。
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int maxNum=nums[0];
for(int i=1;i<nums.size();i++){
//让nums[i]永远是以nums[i]结尾的连续数组的最大值
if(nums[i-1]+nums[i]>nums[i]){
nums[i]=nums[i-1]+nums[i];
}
maxNum=max(maxNum,nums[i]);
}
return maxNum;
}
};