136.只出现一次的数字
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?
示例 1:
输入: [2,2,1]
输出: 1
示例 2:输入: [4,1,2,1,2]
输出: 4来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/single-number
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
一、idea:
哈希表。
二、解法:
位运算
三、代码实现细节的学习:
异或运算的性质:
异或运算的写法也可以学习下。以及网络查询后发现C中没有foreach函数。
int singleNumber(int* nums, int numsSize){
int ret=0,i=0;
while(i<numsSize){
ret^=nums[i++];
}
return ret;
}
169.多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
示例 1:
输入:[3,2,3]
输出:3
示例 2:输入:[2,2,1,1,1,2,2]
输出:2
进阶:
尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/majority-element
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
一、idea:
排序后计算每个数的出现次数,空间复杂度O(1)
int cmp(const void* _a, const void* _b){
return *(int*)_a-*(int*)_b;
}
int majorityElement(int* nums, int numsSize){
qsort(nums,numsSize,sizeof(int),cmp);
int now=nums[0],count=1;
for(int i=1;i<numsSize;i++){
if(now==nums[i]){
count++;
}else{
if(count>numsSize/2){
return now;
}
now=nums[i];
count=1;
}
}
return now;
}
二、解法:
- 哈希表
- 排序
- 随机化
- 分治
- Boyer-Mooer算法
三、代码实现细节的学习:
1、略
2、排序,看了题解后的更新
int cmp(const void* _a, const void* _b){
return *(int*)_a-*(int*)_b;
}
int majorityElement(int* nums, int numsSize){
qsort(nums,numsSize,sizeof(int),cmp);
/*
int now=nums[0],count=1;
for(int i=1;i<numsSize;i++){
if(now==nums[i]){
count++;
}else{
if(count>numsSize/2){
return now;
}
now=nums[i];
count=1;
}
}
*/
return nums[numsSize/2];
}
3、随机化,熟悉一下C中的随机函数
srand(time(0));
int num = rand() % (max - min) + min;
int majorityElement(int* nums, int numsSize){
while(true){
int index=rand()%numsSize;
int count=0;
for(int i=0;i<numsSize;i++){
if(nums[i]==nums[index]){
count++;
}
}
if(count>numsSize/2){
return nums[index];
}
}
return 0;
}
4、分治的格式基本都是和归并类似的格式,用坐标把数组/集合分成两块然后进行递归。
int count_in_range(int* nums, int target, int low, int high){
int count=0;
for(int i=low;i<=high;i++){
if(target==nums[i]){
count++;
}
}
return count;
}
int whosTheMajority(int* nums, int low, int high){
if(low>=high){
return nums[low];
}
int mid=(low+high)/2;
int left_majority=whosTheMajority(nums,low,mid);
int right_majority=whosTheMajority(nums,mid+1,high);
if(count_in_range(nums,left_majority,low,high)>(high-low+1)/2) return left_majority;
if(count_in_range(nums,right_majority,low,high)>(high-low+1)/2) return right_majority;
return -1;
}
int majorityElement(int* nums, int numsSize){
return whosTheMajority(nums, 0, numsSize-1);
}
5、Boyer-Mooer算法,可以视为求众数的特殊方法吗?
int majorityElement(int* nums, int numsSize){
int candidate=-1;
int count=0;
for(int i=0;i<numsSize;i++){
if(nums[i]==candidate){
count++;
}else if(--count<0){
candidate=nums[i];
count=1;
}
}
return candidate;
}
15.三数之和
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组。
示例 1:
输入:nums = [-1,0,1,2,-1,-4]
输出:[[-1,-1,2],[-1,0,1]]
示例 2:输入:nums = []
输出:[]
示例 3:输入:nums = [0]
输出:[]
提示:
0 <= nums.length <= 3000
-105 <= nums[i] <= 105来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/3sum
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
一、idea:
无思路
二、解法:
排序+双指针
三、代码实现细节的学习:
首先理解题解——先固定一个数,然后剩下的两个数按两数之和来进行判定,还是要利用控制变量变成自己已经会做的题。最后还有去重操作靠着排序和first[i]!=first[i-1]来操作。然后用双指针降低时间复杂度。
/**
* Return an array of arrays of size *returnSize.
* The sizes of the arrays are returned as *returnColumnSizes array.
* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
*/
int cmp(const void* _a, const void* _b){
return *(int *)_a-*(int *)_b;
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
*returnColumnSizes=malloc(sizeof(int)*numsSize*numsSize);
*returnSize=0;
if(numsSize<3||nums==NULL) return NULL;
qsort(nums,numsSize,sizeof(int),cmp);
int **ret=malloc(sizeof(int*)*numsSize*numsSize);
for(int first=0;first<numsSize;first++){
if(nums[first]>0) return ret;
if(first>0&&nums[first]==nums[first-1]){
continue;
}
int targetSum=-nums[first];
int second=first+1;
int third=numsSize-1;
/*
while(second<third){
if(second>first+1&&nums[second]==nums[second-1]){
second++;
continue;
}
if(nums[second]+nums[third]==targetSum){
ret[*returnSize]=malloc(sizeof(int)*3);
ret[*returnSize][0]=nums[first];
ret[*returnSize][1]=nums[second];
ret[*returnSize][2]=nums[third];
(*returnColumnSizes)[(*returnSize)++]=3;
}else if(nums[second]+nums[third]>targetSum){
third--;
}else{
second++;
}
}
*/
for(int second=first+1;second<numsSize;second++){
if(second>first+1&&nums[second]==nums[second-1]){
//这里应该是让second只和第二圈的数比较
continue;
}
//int third=numsSize-1;不是每一次第二圈循环都从最后一个,注意这应该放在外圈
while(second<third&&nums[second]+nums[third]>targetSum){
//因为是排好序的,如果不可能出现小于的情况,所以只用考虑往小了靠
third--;
}
if(second==third){
break;
}
if(nums[second]+nums[third]==targetSum){
ret[*returnSize]=malloc(sizeof(int)*3);
ret[*returnSize][0]=nums[first];
ret[*returnSize][1]=nums[second];
ret[*returnSize][2]=nums[third];
(*returnColumnSizes)[(*returnSize)++]=3;
}
}
}
return ret;
}
还有一个普通双指针的写法熟悉一下。
nums[second]==nums[++second];①
nums[++second]==nums[second];②
这两句是有区别的,因为整个式子从左开始计算,如果是①式,second便还是原本的,而②式右边的second是已经更改后的,所以②式中的判断等于肯定是true,如有错误,欢迎指正。
/**
* Return an array of arrays of size *returnSize.
* The sizes of the arrays are returned as *returnColumnSizes array.
* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
*/
int cmp(const void* _a, const void* _b){
return *(int *)_a-*(int *)_b;
}
int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes){
*returnColumnSizes=malloc(sizeof(int)*numsSize*numsSize);
*returnSize=0;
if(numsSize<3||nums==NULL) return NULL;
qsort(nums,numsSize,sizeof(int),cmp);
int **ret=malloc(sizeof(int*)*numsSize*numsSize);
for(int first=0;first<numsSize;first++){
if(nums[first]>0) return ret;
if(first>0&&nums[first]==nums[first-1]){
continue;
}
int targetSum=-nums[first];
int second=first+1;
int third=numsSize-1;
while(second<third){
if(nums[second]+nums[third]==targetSum){
ret[*returnSize]=malloc(sizeof(int)*3);
ret[*returnSize][0]=nums[first];
ret[*returnSize][1]=nums[second];
ret[*returnSize][2]=nums[third];
(*returnColumnSizes)[(*returnSize)++]=3;
while(second<third&&nums[second]==nums[++second]);
while(second<third&&nums[third]==nums[--third]);
}else if(nums[second]+nums[third]>targetSum){
third--;
}else{
second++;
}
}
}
return ret;
}