这里刷题的顺序是随机的,按标题进行筛选 ,比如今天刷的是数组有关的easy题。
88.合并两个有序数组
归并思想,双指针。使用一个辅助数组进行存排好后的序列。
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n) {
int *arr = (int*)malloc(sizeof(int)*(m+n));
int index=0,left=0,right=0;
while(index<nums1Size&&left<m&&right<n){
if(nums1[left]<nums2[right]){
arr[index++]=nums1[left++];
}else if(nums1[left]>nums2[right]){
arr[index++]=nums2[right++];
}else{
arr[index++]=nums1[left++];
arr[index++]=nums2[right++];
}
}
while(left<m) arr[index++]=nums1[left++];
while(right<n) arr[index++]=nums2[right++];
for(int i=0;i<index;i++){
nums1[i] = arr[i];
}
}
136.只出现一次的数字
注意排序的写法,遍历数组,用target记录上一个数字。
int comp(void *a,void *b){
return *(int *)a-*(int *)b;
}
int singleNumber(int* nums, int numsSize) {
qsort(nums,numsSize,sizeof(int),comp);//升序
int ans=nums[0];
for(int i=1;i<numsSize;i++){
if(ans!=nums[i]){
break;
}
i++;
ans=nums[i];
}
return ans;
}
169.多数元素
1.排序
找数组中个数大于n/2的元素。
由于多数的个数大于n/2,所以排序之后,如果存在多数,n/2的位置必然是多数。
int comp(void *a,void *b){
return *(int *)a-*(int *)b;
}
int majorityElement(int* nums, int numsSize) {
qsort(nums,numsSize,sizeof(int),comp);
return nums[numsSize/2];
}
2.摩尔投票法
将第一个元素设为标志初始值,标志数量设为1,遍历元素,当元素与标志值不同时标志值--,相同时++,当标志值--时,判断标志值是否=0,等于零更换标志为nums[i],数量置1.最后返回的标志即大于n/2.
int majorityElement(int* nums, int numsSize) {
int target=nums[0],flag=1;
for(int i=1;i<numsSize;++i){
if(target==nums[i]){
flag++;
}else{
flag--;
if(flag==0){
target=nums[i];
flag=1;
}
}
}
return target;
}
217.存在重复元素
排序+判断
int cmp(void *a,void *b){
return *(int*)a-*(int*)b;
}
bool containsDuplicate(int* nums, int numsSize) {
qsort(nums,numsSize,sizeof(int),cmp);
for(int i=1;i<numsSize;++i){
if(nums[i-1]==nums[i]){
return true;
}
}
return false;
}
219.存在重复元素II
给你一个整数数组
nums
和一个整数k
,判断数组中是否存在两个 不同的索引i
和j
,满足nums[i] == nums[j]
且abs(i - j) <= k
。如果存在,返回true
;否则,返回false
。
此题涉及下标,不能进行排序,因此使用滑动窗口。
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
unordered_set<int> s;
int n=nums.size();
for(int i=0;i<n;++i){
if(i>k){
s.erase(nums[i-k-1]);
}
if(s.count(nums[i])){
return true;
}
s.emplace(nums[i]);
}
return false;
}
};
另一种解法,用哈希表记录每一个元素,及其下标。
class Solution {
public:
bool containsNearbyDuplicate(vector<int>& nums, int k) {
unordered_map<int, int> dictionary;
int length = nums.size();
for (int i = 0; i < length; i++) {
int num = nums[i];
if (dictionary.count(num) && i - dictionary[num] <= k) {
return true;
}
dictionary[num] = i;
}
return false;
}
};
1287.找有序数组中超过25%的元素
注意当数组长度小于4时单独处理,不然有一些用例通不过。思路和前几题找数的题很类似。
int findSpecialInteger(int* arr, int arrSize) {
if(arrSize<4) return arr[0];//如果数组长度小于4,又因题目说存在这个数,因此情况必然为[1]/[1,1]/[1,1,1]这三种
int target=arr[0];
int count=1;
for(int i=1;i<arrSize;++i){
if(arr[i]!=target){
target=arr[i];
count=1;
}else{
count++;
if(count>arrSize/4){
return target;
}
}
}
return -1;
}
1295.统计位数为偶数的数字
此题为简单模拟即可。
bool fun(int num){
int count=0;
while(num){
num/=10;
count++;
}
if(count%2==0){
return true;
}else{
return false;
}
}
int findNumbers(int* nums, int numsSize) {
int ans=0;
for(int i=0;i<numsSize;++i){
if(fun(nums[i])){
ans++;
}
}
return ans;
}
1304.和为0的N个不同整数
模拟。
int* sumZero(int n, int* returnSize){
*returnSize=n;
int* ans=(int *)malloc(sizeof(int)*n);
for(int i=1;i<=n/2;++i){
ans[i-1]=i;
ans[n-i]=-i;//每次添加的数刚好能抵消
}
if(n%2==1) ans[n/2]=0;//奇数则填0
return ans;
}
1331.数组序号转换
首先用一个数组保存排序完的原数组,然后用一个哈希表保存各元素的序号,最后将原属组的元素替换为序号后返回。
class Solution {
public:
vector<int> arrayRankTransform(vector<int>& arr) {
vector<int> sortarr=arr;
sort(sortarr.begin(),sortarr.end());
unordered_map<int,int> mp;//用于记录排好序后的下标值
vector<int> ans(arr.size());
int index=1;//记录下标
for(int i=0;i<sortarr.size();++i){
if(mp.count(sortarr[i])==0){//重复的值不需要记录
mp[sortarr[i]]=index++;
}
}
for(int i=0;i<arr.size();++i){
ans[i]=mp[arr[i]];
}
return ans;
}
};
1346.检查是否存在整数及其两倍的数
直接用暴力法,两个for循环进行判断。
bool checkIfExist(int* arr, int arrSize){
for(int i=0;i<arrSize;++i){
for(int j=0;j<arrSize;++j){
if(i!=j&&arr[i]==arr[j]*2){
return true;
}
}
}
return false;
}
1470.重新排列数组
一次遍历,奇数和偶数下标分开赋值。
int* shuffle(int* nums, int numsSize, int n, int* returnSize){
*returnSize=n*2;
int *arr=(int *)malloc(sizeof(int)*n*2);
for(int i=0;i<n;++i){
arr[2*i]=nums[i];//偶数
arr[2*i+1]=nums[i+n];//奇数
}
return arr;
}
1528.重新排列字符串
同上题,需要注意char[]数组需要多一位,存放‘\0’。
char* restoreString(char* s, int* indices, int indicesSize) {
char* arr=(char*)malloc(sizeof(char)*(indicesSize+1));
for(int i=0;i<indicesSize;++i){
arr[indices[i]]=s[i];
}
arr[indicesSize]='\0';
return arr;
}
1480.一维数组的动态和
此题为前缀和思想的简单题。
int* runningSum(int* nums, int numsSize, int* returnSize){
*returnSize=numsSize;
for(int i=1;i<numsSize;++i){
nums[i]+=nums[i-1];
}
return nums;
}
1502.判断是否是等差数列
排序,然后依次判断。
int cmp(void* a,void* b){
return *(int*)a-*(int*)b;
}
bool canMakeArithmeticProgression(int* arr, int arrSize) {
if(arrSize<=2){
return true;
}
qsort(arr,arrSize,sizeof(int),cmp);
int target=arr[1]-arr[0];
for(int i=2;i<arrSize;++i){
if(arr[i]-arr[i-1]!=target){
return false;
}
}
return true;
}
1539.第K个缺失的数
1.数组作为哈希表
这一解法不太好,因为如果arr中的数字太大,flag数组所占用的空间就会太大 ,但这个题中元素是三位数,所以勉强还可用这个方法。如果实在要用这个方法,就尽量把数组设置得尽量大一些,可以通过更多的测试用例。
int findKthPositive(int* arr, int arrSize, int k){
int flag[3000]={0};
for(int i=0;i<arrSize;++i){
flag[arr[i]]=1;
}
for(int i=1;i<3000;++i){
if(flag[i]==0){
k--;
}
if(k==0){
return i;
}
}
return arr[arrSize-1]+1;
}
2.枚举
该解法比较直观,注意一些细节。
int findKthPositive(int* arr, int arrSize, int k){
int cur=1,p=0,misscount=0,lastmiss=-1;
//cur是当前应该出现的数
//p指向数组中没有匹配的第一个元素
//misscount是缺失的数的个数
//lastmiss是最后一个缺失的数
for(misscount=0;misscount<k;cur++){
if(cur==arr[p]){
if(p+1<arrSize){//p大于数组长度时,p不再增加
p++;
}
}else{
misscount++;
lastmiss=cur;
}
}
return lastmiss;
}
1550.存在连续三个奇数的数组
枚举长度为3的子序列,依次判断即可。
bool threeConsecutiveOdds(int* arr, int arrSize) {
for(int i=2;i<arrSize;++i){
if(arr[i]%2==1&&arr[i-1]%2==1&&arr[i-2]%2==1){
return true;
}
}
return false;
}
1588.所有奇数长度子数组的和
1.暴力解
模拟,需要注意的是for循环的边界条件。
int sumOddLengthSubarrays(int* arr, int arrSize){
int sum=0;
//枚举奇数
for(int i=1;i<=arrSize;i+=2){
for(int k=0;k<=arrSize-i;++k){
for(int j=k;j<k+i;++j){
sum+=arr[j];
}
}
}
return sum;
}
2.前缀和
用一个数组进行计算子数组的前缀和。然后再枚举子数组的起始位置和终止位置。
int sumOddLengthSubarrays(int* arr, int arrSize){
int prefixsum[arrSize+1];
prefixsum[0]=0;
for(int i=0;i<arrSize;++i){
prefixsum[i+1]=prefixsum[i]+arr[i];
}
int sum=0;
for(int start=0;start<arrSize;++start){//枚举起始位置
for(int length=1;start+length<=arrSize;length+=2){//枚举子数组长度
int end=start+length-1;
sum+=prefixsum[end+1]-prefixsum[start];//每次加上子数组之和
}
}
return sum;
}
1608.特殊数组的特征值
给你一个非负整数数组
nums
。如果存在一个数x
,使得nums
中恰好有x
个元素 大于或者等于x
,那么就称nums
是一个 特殊数组 ,而x
是该数组的 特征值 。注意:
x
不必 是nums
的中的元素。
暴力解法,注意两处细节即可。
int specialArray(int* nums, int numsSize){
for(int i=0;i<=numsSize;++i){//枚举x的值,可以等于numsSize
int count=0;
for(int j=0;j<numsSize;++j){
if(nums[j]>=i){
count++;
}
}
if(count==i) return i;//恰好等于,所以必须在循环外面判断
}
return -1;
}