最大子数组和
链接:53. 最大子数组和 53. 最大子数组和 - 力扣(Leetcode)
题目描述:
给你一个整数数组 nums
,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。
示例:
输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
解题思路:
思路一:暴力,遍历n次,记下max的值,在内层循环和累加值比较。
思路二:方法二:分治
1.结束条件,当numsSize==1时直接返回当前值
2.处理左支求Max_ Left
3.处理右支求Max_ Right
4.处理本身,向左求最大和Max_ L然后向右求最大和Max_ R
5.最终结果为MAX(Max_Left, Max_ Right, Max_ R)
代码实现
方法一:
int maxSubArray(vector<int>& nums) {
int i =0;
int j = 0;
int MAX = INT_MIN;
for(int i = 0; i< nums.size(); i++){
int temp = 0;
for(int j = i; j< nums.size(); j++){
temp += nums[j];
if(MAX < temp) MAX = temp;
}
}
return MAX;
}
(实测超时)
方法二:
#define MAX(a,b,c) ((a) > ((b)>(c)?(b):(c)) ? (a) : ((b)>(c)?(b):(c)))
int maxSubArray(int* nums, int numsSize){
int temp = 0;
int i = 0;
int MAX_LEFT = 0;
int MAX_RIGHT = 0;
int MAX_L = 0;
int MAX_R = 0;
if(numsSize == 0 || numsSize == 1) return nums[0];
else {
MAX_LEFT = maxSubArray(&nums[0],(numsSize-1)/2);
MAX_RIGHT = maxSubArray(&nums[(numsSize+1)/2],numsSize/2);
}
MAX_L = nums[(numsSize-1)/2];
temp = 0;
for(i = (numsSize-1)/2; i >= 0; i--){
temp += nums[i];
MAX_L = MAX_L>temp?MAX_L:temp;
}
MAX_R = MAX_L;
temp = MAX_L;
for(i =(numsSize+1)/2; i < numsSize; i++ ){
temp+=nums[i];
MAX_R = MAX_R>temp?MAX_R:temp;
}
return MAX(MAX_LEFT,MAX_RIGHT,MAX_R);
}
原地移除元素
链接:27. 移除元素 27. 移除元素 - 力扣(Leetcode)
题目描述:
给你一个数组 nums
和一个值 val
,你需要原地移除所有数值等于 val
的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1)
额外空间并原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
示例:
输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
解题思路:
思路:一个(慢) num指针为数组本身进行复写,一个(快) p指针不断移动并判断是否等于val的值。一旦快指针所指向的值不等于val ,则进行复写,将快指针所指向的值复写慢指针所指向的值,且计数器加一。
(注意顺序:先*nums=p[i] ,后nums++ ;因为慢指针的最后一项总是待复写的位置,所以若快指针所
指向的值不等于val时,先将快指针的值复写慢指针的值,再将慢指针往后挪一位)
代码实现
int removeElement(int* nums, int numsSize, int val){
int count = 0;int slow = 0;
for(int i = 0;i<numsSize;i++){
if(nums[i] != val){
nums[slow] = nums[i];
slow ++;
count ++;
}
}
return count;
}
合并两个有序数组
链接:88. 合并两个有序数组 88. 合并两个有序数组 - 力扣(Leetcode)
题目描述:
给你两个按 非递减顺序 排列的整数数组 nums1
和 nums2
,另有两个整数 m
和 n
,分别表示 nums1
和 nums2
中的元素数目。
请你 合并 nums2
到 nums1
中,使合并后的数组同样按 非递减顺序 排列。
注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1
中。为了应对这种情况,nums1
的初始长度为 m + n
,其中前 m
个元素表示应合并的元素,后 n
个元素为 0
,应忽略。nums2
的长度为 n
。
示例:
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
解题思路:
思路一:由于数组1有足够空间,分别从末端遍历存入数组1。
代码实现
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
int M = m-1;
int N = n-1;
int cur = m+n-1;
while(M >= 0 && N >= 0){
if(nums1[M] >= nums2[N]){
nums1[cur--] = nums1[M--];
}else {
nums1[cur--] = nums2[N--];
}
}
while(N>=0){
nums1[cur--] = nums2[N--];
}
}
查找常用字符
链接:1002. 查找共用字符 88. 合并两个有序数组 - 力扣(Leetcode)1002. 查找共用字符 - 力扣(Leetcode)88. 合并两个有序数组 - 力扣(Leetcode)
题目描述:
给你一个字符串数组 words
,请你找出所有在 words
的每个字符串中都出现的共用字符( 包括重复字符),并以数组形式返回。你可以按 任意顺序 返回答案。例如,如果一个字符在每个字符串中出现3次,但不是4次,则需要在最终答案中包含该字符3次。
示例:
输入:words = ["bella","label","roller"]
输出:["e","l","l"]
解题思路:
思路一:维护两个数组,其中一个用于统计每个字符串的字母频率,另一个用以更新最小值,最后输出char **;
代码实现
char ** commonChars(char ** words, int wordsSize, int* returnSize){
int minfreq[26], freq[26];
for(int i = 0; i< 26;++i){
minfreq[i] = INT_MAX;
freq[i] = 0;
}
for(int i = 0;i<wordsSize;++i){
memset(freq,0,sizeof(freq));
int n = strlen(words[i]);
for(int j =0; j<n; ++j){
++freq[words[i][j] - 'a'];
}
for(int j = 0;j<26; ++j){
minfreq[j] = fmin(minfreq[j],freq[j]);
}
}
int sum = 0;
for(int i=0; i< 26;++i){
sum += minfreq[i];
}
char** ans = malloc(sizeof(char*) * sum);
*returnSize = 0;
for(int i = 0; i<26; ++i){
for(int j = 0; j<minfreq[i]; ++j){
ans[*returnSize] = malloc(sizeof(char) * 2);
ans[*returnSize][0] = i + 'a';
ans[*returnSize][1] = 0;
(*returnSize)++;
}
}
return ans;
}
寻找数组的中心索引
链接:724. 寻找数组的中心下标 724. 寻找数组的中心下标 - 力扣(Leetcode)
题目描述:
给你一个整数数组 nums
,请计算数组的 中心下标 。
数组 中心下标 是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果中心下标位于数组最左端,那么左侧数之和视为 0
,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。
如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1
。
示例:
输入:nums = [1, 7, 3, 6, 5, 6]
输出:3
解释:
中心下标是 3 。
左侧数之和 sum = nums[0] + nums[1] + nums[2] = 1 + 7 + 3 = 11 ,
右侧数之和 sum = nums[4] + nums[5] = 5 + 6 = 11 ,二者相等。
解题思路:
思路一:滑动窗口 先设定一个初始位置0(坑啊,题目出的有问题,应该从1开始才对,没办法,题目
认为0左边没元素也符合) 以其为中心分别计算左、右的和,然后比较不相等就右移,更新左、右和
即可。
代码实现
int pivotIndex(int* nums, int numsSize){
int left = 0;
int right = 0;
for(int i = 0;i<numsSize;++i){
right += nums[i];
}
right -= nums[0];
if(right == 0) return 0;
for(int i = 1;i<numsSize; ++i){
left += nums[i-1];
right -= nums[i];
if(left == right) return i;
}
return -1;
}
找出数组中两个无重复的数字
链接:剑指 Offer 56 - I. 数组中数字出现的次数 剑指 Offer 56 - I. 数组中数字出现的次数 - 力扣(Leetcode)
题目描述:
一个整型数组 nums
里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
示例:
输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]
解题思路:
思路:利用异或^运算的特性
1、0和任何数异或等于该数
2、任何数和自身异或等于0
3、异或运算满足交换律
1、当将一个数组的数全部按位异或后,可以将成对的数放在前面先运算,而成对的数经过上述1,2会得到0 ,也就达到了消去成对的数的目的。此时数组中剩下两个不同的数异或,得到的结果mask是这两个数不同的位上值为1 , 相同的为0.
2、但这样没办法把两个数分离出来。既然这两个不同的数必然有位是不同的,并且异或的结果也告诉我们哪些位不同。我们不妨以mask的最低的值为1的位(设为a0位)来区分这两个数,其中一个数a0位等于1 ,另一个等于0。其中通过位运算x & (-x)得到a0= 1 ,其他位为0的结果。
3、 同样我们将数组中其他的数,也分成两组: a0 = 0组和a0= 1组,这样保证了两个不同的数分在两组,也保证了成对的数必在其中一组而不会一对数分在两组。
4、分别对两组的数进行异或运算,最后得到的两个数即所求。
代码实现
int* singleNumbers(int* nums, int numsSize, int* returnSize){
int mask = 0;
for(int i = 0; i< numsSize; ++i){
mask ^= nums[i];
}
mask = mask & (-mask);
int m1 = 0;
int m2 = 0;
for(int i = 0; i< numsSize; ++i){
if(nums[i] & mask){
m1 ^= nums[i];
}else{
m2 ^= nums[i];
}
}
*returnSize = 2;
int *a = (int *)malloc(2*sizeof(int));
a[0] = m1;
a[1] = m2;
return a;
}
找出数组中三个无重复的数字
链接:
剑指 Offer 56 - II. 数组中数字出现的次数 II
剑指 Offer 56 - I. 数组中数字出现的次数 - 力扣(Leetcode)剑指 Offer 56 - II. 数组中数字出现的次数 II - 力扣(Leetcode)剑指 Offer 56 - I. 数组中数字出现的次数 - 力扣(Leetcode)
题目描述:
在一个数组 nums
中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次的数字。
示例:
输入:nums = [3,4,3,3]
输出:4
解题思路:
理论基础:某一数字出现3次,则他们每-位的和分别可以被3整除如数字7 : 0111 ,第0位为1 , 3个1加起来为11 ,可以被三整除。第二第三位同理。
步骤:
1.分别给数组中所有数字不同位分别求和,结果记录为temp , int型要分别求32次。
2.若第i位的求和结果temp能被3整除,说明只出现了1次的那个数字该位为0 ,否则为1。
3.根据第二部结果,给result的第i位置1或0。( 置0可以不做处理)。
代码实现
int singleNumber(int* nums, int numsSize){
int result = 0;
for(int i = 0; i< 32; ++i){
int temp = 0;
for(int j = 0; j<numsSize; ++j){
temp += (nums[j]>>i)&1;
}
if(temp % 3) result+=(1<<i);
}
return result;
}
数组中缺失的元素
链接:
268. 丢失的数字268. 丢失的数字 - 力扣(Leetcode)
题目描述:
给定一个包含 [0, n]
中 n
个数的数组 nums
,找出 [0, n]
这个范围内没有出现在数组中的那个数。
示例:
输入:nums = [3,0,1]
输出:2
解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中
解题思路:
1、哈希数组
2、异或
3、求和取差
代码实现
方法一
int missingNumber(int* nums, int numsSize){
int hash[10000] = {0};
for(int i = 0; i<numsSize; ++i){
hash[nums[i]]++;
}
for(int i = 0;i<=numsSize; ++i){
if(hash[i] == 0) return i;
}
return -1;
}
方法二
int missingNumber(int* nums, int numsSize){
int res = numsSize;
for(int i = 0; i< numsSize; ++i){
res ^= nums[i];
res ^= i;
}
return res;
}
方法三
int missingNumber(int* nums, int numsSize){
int Sum = (numsSize+1)*numsSize/2;
for(int i =0; i< numsSize;++i){
Sum -= nums[i];
}
return Sum;
}
测试结果哈希表的时间空间使用是最小的,原因可能是哈希表不需要完全遍历。
按奇偶排序数组
链接:
905. 按奇偶排序数组905. 按奇偶排序数组 - 力扣(Leetcode)
题目描述:
给你一个整数数组 nums
,将 nums
中的的所有偶数元素移动到数组的前面,后跟所有奇数元素。
返回满足此条件的 任一数组 作为答案。
示例:
输入:nums = [3,1,2,4]
输出:[2,4,3,1]
解释:[4,2,3,1]、[2,4,1,3] 和 [4,2,1,3] 也会被视作正确答案。
解题思路:
维护头尾两个下标,遍历原数组,将偶数从前往后放,奇数从后往前放。
代码实现
int* sortArrayByParity(int* A,int ASize,int* returnSize) {
*returnSize = ASize;
if (ASize< 2) return A;
int *arr = (int *)malloc(sizeof(int)*ASize);
int head = 0,tail = ASize-1;
for(int i = 0;i<ASize;i++){
if(A[i]%2==0)
arr[head++] = A[i];
else
arr[tail--] = A[i];
}
return arr;
}
数组是否存在重复元素
链接:
219. 存在重复元素 II219. 存在重复元素 II - 力扣(Leetcode)
题目描述:
给你一个整数数组 nums
和一个整数 k
,判断数组中是否存在两个 不同的索引 i
和 j
,满足 nums[i] == nums[j]
且 abs(i - j) <= k
。如果存在,返回 true
;否则,返回 false
。
示例:
输入:nums = [1,2,3,1], k = 3
输出:true
输入:nums = [1,0,1,1], k = 1
输出:true
解题思路:
使用uthash.h头文件,构建C哈希表。(模板)
代码实现
typedef struct hash{
int key; //键
int index; //索引值
UT_hash_handle hh; //让结构体哈希柄
} *hash_ptr;
bool containsNearbyDuplicate(int* nums, int numsSize, int k){
hash_ptr p=NULL,tables =NULL ;
for(int i=0;i <numsSize;i++){
if(tables) HASH_FIND_INT(tables, &(nums[i]),p);
//如果哈希表中已经存在这个元素,判断当前正在放入的和已经放入的索引值的差值
if(p&&(i-p->index)<=k) return true;
p=(hash_ptr)malloc(sizeof(*p));
p->key=nums [i] ;
p->index=i ;
HASH_ADD_INT(tables,key, p);
}
return false;
}
有序数组出现次数超过25%元素
链接:
1287. 有序数组中出现次数超过25%的元素1287. 有序数组中出现次数超过25%的元素 - 力扣(Leetcode)
题目描述:
给你一个非递减的 有序 整数数组,已知这个数组中恰好有一个整数,它的出现次数超过数组元素总数的 25%。
请你找到并返回这个整数
示例:
输入:arr = [1,2,2,6,6,6,6,7,10]
输出:6
解题思路:
方法一:将每个元素放进数组,遍历哈希表求次数相等的元素。
方法二:数组有序,且某元素出现次数超过25%。那么对于此元素第1次出现位置,加25%数组长度,必定仍为它自身。
代码实现
方法一
int findSpecialInteger(int* arr, int arrSize){
if(arrSize < 1) return-1;
int flag[100001] = {0};
for(int i = 0; i<arrSize; ++i){
flag[arr[i]]++;
}
int cnt = arrSize*0.25;
for(int i = 0; i<=100000; ++i){
if(flag[i] > cnt) return i;
}
return -1;
}
方法二
int findSpecialInteger(int* arr, int arrsize){
for(int*p=arr,*q=arr+arrsize/4;;p++,q++)
if (*p == *q) return *p;
return 0;
}
有效的山脉数组
链接:
941. 有效的山脉数组941. 有效的山脉数组 - 力扣(Leetcode)
题目描述:
给定一个整数数组 arr
,如果它是有效的山脉数组就返回 true
,否则返回 false
。
让我们回顾一下,如果 arr
满足下述条件,那么它是一个山脉数组:
arr.length >= 3
- 在
0 < i < arr.length - 1
条件下,存在i
使得:arr[0] < arr[1] < ... arr[i-1] < arr[i]
arr[i] > arr[i+1] > ... > arr[arr.length - 1]
示例:
输入:arr = [2,1]
输出:false
解题思路:
方法:遍历一次:上山步数+下山步数 = 总长-1
代码实现
bool validMountainArray(int* arr, int arrSize){
if(arrSize < 3) return false;
int dec = 0;
int inc = 0;
for(int i = 0; i< arrSize-1; ++i){
if(arr[i]<arr[i+1] && dec==0) inc++;
else if(arr[i]>arr[i+1] && inc>0) dec++;
}
if(inc + dec == arrSize-1 && inc<arrSize-1 && dec<arrSize-1 && inc && dec) return true;
return false;
}
最长连续递增序列
链接:
674. 最长连续递增序列674. 最长连续递增序列 - 力扣(Leetcode)
题目描述:
给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度。
连续递增的子序列 可以由两个下标 l
和 r
(l < r
)确定,如果对于每个 l <= i < r
,都有 nums[i] < nums[i + 1]
,那么子序列 [nums[l], nums[l + 1], ..., nums[r - 1], nums[r]]
就是连续递增子序列。
示例:
输入:nums = [1,3,5,4,7]
输出:3
解释:最长连续递增序列是 [1,3,5], 长度为3。
尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为 5 和 7 在原数组里被 4 隔开。
解题思路:
维护一个递增子数组,分别统计其长度,比较取最大值。
代码实现
int findLengthOfLCIS(int* nums, int numsSize){
int mlen = 1;
for(int i = 0 ; i<numsSize-1;i++){
int len = 1;
while(i<numsSize-1 && nums[i] < nums[i+1]){
len++;
i++;
}
mlen = len>mlen?len:mlen;
}
return mlen;
}