day15_LC学习计划:数据结构基础

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;
}

二、解法:

  1. 哈希表
  2. 排序
  3. 随机化
  4. 分治
  5. 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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值