Leetcode刷题笔记

Leetcode刷题笔记

前言

今天是2023年4月19号,大二下了,为之后的就业做准备,开始刷题学习,做笔记打卡,加油!

模板:

题目:
我的思路及解法
代码

在这里插入代码片

复杂度分析
时间复杂度:
空间复杂度:
更优解法:
思路及算法

代码:


复杂度分析:
时间复杂度:
空间复杂度:





数组篇

题号题目
1两数之和
485最大连续 1 的个数
495提莫攻击
414第三大的数
628三个数的最大乘积
645错误的集合
697数组的度
448找到所有数组中消失的数字
442数组中重复的数据
41缺失的第一个正数
274H指数
453最小操作次数使数组元素相等
665
283
118
119
1. 两数之和

万事开头难,那就以一道简单的题开启刷题之旅吧!
题目:给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
我的思路及解法:我第一下想到就是两重循环,直接暴力枚举,依次遍历每两个元素的组合,把两数之和等于target的下标记录到数组中,返回数组。
代码

class Solution {
    public int[] twoSum(int[] nums, int target) {
int[] arr = new int[2];
        for(int i = 0;i<nums.length;i++){
            for(int j = i + 1;j<nums.length;j++){
                if(nums[i]+nums[j]==target){
                    arr[0] = i;
                    arr[1] = j;
                    return arr;
                }
            }
        }
        return arr;
    }
}

复杂度分析:
时间复杂度:O( N 2 N^2 N2),其中N是数组中的元素数量。最坏的情况下数组中的任意两个数都要被匹配一次。
空间复杂度:O(1)

更优解法:哈希表
思路及算法
注意到方法一的时间复杂度较高的原因是寻找 target - x 的时间复杂度过高。因此,我们需要一种更优秀的方法,能够快速寻找数组中是否存在目标元素。如果存在,我们需要找出它的索引。
使用哈希表,可以将寻找 target - x 的时间复杂度降低到从 O(N)降低到O(1).
这样我们创建一个哈希表,对于每一个 x,我们首先查询哈希表中是否存在 target - x,然后将 x 插入到哈希表中,即可保证不会让 x 和自己匹配。
代码:

class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>();
        for (int i = 0; i < nums.length; ++i) {
            if (hashtable.containsKey(target - nums[i])) {
                return new int[]{hashtable.get(target - nums[i]), i};
            }
            hashtable.put(nums[i], i);
        }
        return new int[0];
    }
}

复杂度分析:
时间复杂度:O(N),其中N是数组中的元素数量。对于每一个元素 x,我们可以 O(1)
地寻找 target - x。
空间复杂度:O(N),其中N是数组中的元素数量,主要为哈希表的开销.

485. 最大连续1的个数

题目:给定一个二进制数组 nums , 计算其中最大连续 1 的个数。
我的思路及解法:直接用一次遍历,设置一个maxCount和max,记录当前出现连续1的个数和最大连续1的个数。当前元素为1时,maxCountt++,当nums[i]为0时,将记录到的连续1个数maxCountt与max比较,count>max的话则更新max,maxCount重置为0,继续遍历。遍历结束,返回最大值max。
代码

class Solution {
    public int findMaxConsecutiveOnes(int[] nums) {
int maxCount=0;
int max=0;
for(int i=0;i<nums.length;i++){
    if(nums[i]==1){
        maxCount++;
    }else{
      max=Math.max(maxCount,max);
        maxCount=0;
    }
    max=Math.max(maxCount,max);
}    
return max;
    }
}

复杂度分析
时间复杂度:O(n),其中 n 是数组的长度。需要遍历数组一次。
空间复杂度:O(1)

495.提莫攻击

题目:
在《英雄联盟》的世界中,有一个叫 “提莫” 的英雄。他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。
当提莫攻击艾希,艾希的中毒状态正好持续 duration 秒。
正式地讲,提莫在 t 发起攻击意味着艾希在时间区间 [t, t + duration - 1](含 t 和 t + duration - 1)处于中毒状态。如果提莫在中毒影响结束 前 再次攻击,中毒状态计时器将会 重置 ,在新的攻击之后,中毒影响将会在 duration 秒后结束。
给你一个 非递减 的整数数组 timeSeries ,其中 timeSeries[i] 表示提莫在 timeSeries[i] 秒时对艾希发起攻击,以及一个表示中毒持续时间的整数 duration 。
返回艾希处于中毒状态的 总 秒数。
timeSeries[i]>poisoned在这里插入图片描述

我的思路及解法
对数组进行一次遍历便能计算出中毒的持续时间

  • 如果他当前处于未中毒状态时(timeSeries[i]>poisoned),则此时他中毒的持续时间应增加duration,同时更新此次中毒的结束时间为poisoned=timeSeries[i]+duration。
  • 如果他当前处于中毒状态(即上一次中毒的结束时间在此次再中毒时刻之前,timeSeries[i]<poisoned),本次再中毒的结束时间为timeSeries[i]+duration,上一次中毒的结束时间为poisoned,因此本次增加的中毒时间为timeSeries[i]+duration-poisoned,继续更新本次中毒结束时间,poisoned=timeSeries[i]+duration。
  • 将每次中毒后增加的持续时间相加即为总中毒时间。

代码

class Solution {
public int findPoisonedDuration(int[] timeSeries, int duration) {
int toxicTime=0;//中毒总时间
int poisoned=0;//恢复为 未中毒/中毒结束的时间
for(int i=0;i<timeSeries.length;i++){
    if(timeSeries[i]>poisoned){
        toxicTime+=duration;
        poisoned=timeSeries[i]+duration;
    }else{
        toxicTime+=timeSeries[i]+duration-poisoned;
        poisoned=timeSeries[i]+duration;
    }
}
return toxicTime;
    }
}

复杂度分析
时间复杂度:O(n),n为数组timeSeries的长度,只需遍历一次数组即可
空间复杂度:O(1)

414.第三大的数

题目:给你一个非空数组,返回此数组中 第三大的数 。如果不存在,则返回数组中最大的数。
在这里插入图片描述

我的思路及解法:题目需要排序和去重,所以我第一就想到了用TreeSet集合。TreeSet不包含重复元素,且元素按照自然排序进行排序,这里是升序(如1,2,3,4).
每次添加元素到集合中,集合中的第一个元素是最低的,最后一个元素是最高的。
若添加元素到集合中使集合长度大于3,则每次都删除掉排序后的第一个元素,使集合长度一直保持为3,遍历结束时返回的.first()即第三大元素。
若集合长度小于3,则返回的.last()即最大元素
代码

class Solution {
    public int thirdMax(int[] nums) {
TreeSet<Integer> ts=new TreeSet<Integer>();
for(int i:nums){
    ts.add(i);
    if(ts.size()>3){
        ts.remove(ts.first());
    }

}
    return ts.size()==3?ts.first():ts.last();
}
}

复杂度分析
时间复杂度:O(n),n为nums数组的长度
空间复杂度:O(1)

628.三个数的最大乘积

题目:给你一个整型数组 nums ,在数组中找出由三个数组成的最大乘积,并输出这个乘积。
我的思路及解法:对数组进行从小到大排序
当数组中有正数和负数的时候,要看绝对值的大小,例如-3,-2,-1,1,2,3
负数越小绝对值越大,最大值为max(两个最小负数之积×最大整数,3个最大正数之积)
代码

class Solution {
    public int maximumProduct(int[] nums) {
Arrays.sort(nums);
int n=nums.length;
return Math.max(nums[0]*nums[1]*nums[n-1],nums[n-3]*nums[n-2]*nums[n-1]);
    }
}

复杂度分析
时间复杂度:O(N logN),其中N为数组的长度,排序需要O(N logN)的时间
空间复杂度:O(logN),主要为排序的空间开销

645.错误的集合

题目:集合 s 包含从 1 到 n 的整数。不幸的是,因为数据错误,导致集合里面某一个数字复制了成了集合里面的另外一个数字的值,导致集合 丢失了一个数字 并且 有一个数字重复 。
给定一个数组 nums 代表了集合 S 发生错误后的结果。
请你找出重复出现的整数,再找到丢失的整数,将它们以数组的形式返回。
在这里插入图片描述

我的思路及解法:找重复元素:遍历数组,前后两个数值相等时该数值即为重复元素。
找缺失元素:由题可知正常情况下数组是连续的。定义两个“指针”,prev=0,tail为数组首元素。通过遍历数组两指针向后顺移。
1<=缺失元素<n:当tail-prev=2时,缺失元素即为tail-1;
缺失元素==n时,即nums[n-1]!=n,缺失元素即为n
代码

class Solution {
    public int[] findErrorNums(int[] nums) {
        int i;
        int[] errorSet={0,0};
 int prev=0;
 int tail=0;
        Arrays.sort(nums);
        for(i=0;i<nums.length;i++){
tail=nums[i];
if(tail==prev){
    errorSet[0]=prev;
}
if(tail-prev>1){
    errorSet[1]=tail-1;
}
prev=tail;
        }
        if(nums[i-1]!=i){
            errorSet[1]=i;
        }
    return errorSet;
    }
}

复杂度分析
时间复杂度:O(n logn),其中n是数组num的长度。排序需要O(nlogn)的时间,遍历数组找到错误的集合需要O(n)的时间,所以总时间复杂度为O(nlogn)
空间复杂度:O(logn),其中n是数组num的长度,排序需要O(logn)的空间

695.数组的度

题目:给定一个非空且只包含非负数的整数数组 nums,数组的 度 的定义是指数组里任一元素出现频数的最大值。
你的任务是在 nums 中找到与 nums 拥有相同大小的度的最短连续子数组,返回其长度。
在这里插入图片描述

我的思路及解法:很惭愧,这道难度为简单的题我都不会做,想了好久有思路就是不知道怎么用代码写出来,看来还是我的语言基础太脆弱了,一时不知道要用到哪个知识点,看了题解才豁然开朗,顺便复习了一下map的用法。这道题我是学着题解的思路写的,虽然不是自己想出来的但是学习别人的东西,学进了也就是自己了的吧。以下是题解的思路和解法。
在这里插入图片描述

代码

class Solution {
    public int findShortestSubArray(int[] nums) {
        int max=0;
        int minLen=0;
Map<Integer,int[]> map=new HashMap<Integer,int[]>();
for(int i=0;i<nums.length;i++){
    if(map.containsKey(nums[i])){
        map.get(nums[i])[0]++;
        map.get(nums[i])[2]=i;
    }else{
       map.put(nums[i], new int[]{1, i, i});
    }
}
Set<Integer> keyset=map.keySet();
for(Integer key:keyset){
if(max<map.get(key)[0]){
    max=map.get(key)[0];
    minLen=map.get(key)[2]-map.get(key)[1]+1;
}else if(max==map.get(key)[0]&&(map.get(key)[2]-map.get(key)[1]+1)<minLen){
  minLen=map.get(key)[2]-map.get(key)[1]+1;
}
}
return minLen;
    }
}

复杂度分析
时间复杂度:O(n),其中n为原数组的长度,我们需要遍历原数组和哈希表各一次,他们的大小均为O(n)
空间复杂度:O(n),其中n为原数组的长度,最坏情况下,哈希表和原数组等大。


模板:

448.找到数组中所有消失的数字

题目:在这里插入图片描述

我的思路及解法:看到这道题,我第一秒想到的就是暴力解法哈哈哈,我的能力只允许我想到暴力解法了。已知题目:nums[i]在[1,n]之中,我设置了双重循环,外层是[1,n]里的数字,每次取一个数字i,遍历所有数组中的元素,若没有匹配上则说明缺失了i,将他添加入list集合中,最后将集合返回,思路很简单,代码也很简单,一次执行就能通过,但是数据量一大起来消耗时间太长了,leetcode的控制台直接显示超出时间限制了,我自己在idea上面是可行的,可是消耗时间成本太大了,我先将他传上来然后再想一下怎么优化吧。
代码

class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {
List<Integer> missingList=new ArrayList();
int count=0;
int flag=0;
for(int i=1;i<=nums.length;i++){
    flag=0;
    for(int j=0;j<nums.length;j++){
if(nums[j]==i){
flag=1;
break;
}else{
    continue;
}
    }
    if(flag==0){
    missingList.add(i);
}
}
return missingList;
    }
}

复杂度分析
时间复杂度:O( N 2 N^2 N2),双重循环,n为数组长度。
空间复杂度:O(1)

更优解法:原地修改
思路及算法:参考leetcode题库448官方解答
在这里插入图片描述

代码:

class Solution {
    public List<Integer> findDisappearedNumbers(int[] nums) {
 List<Integer> missingList=new ArrayList();
int n=nums.length;
int x=0;
int i=0;
for(i=0;i<n;i++){
    x=(nums[i]-1)%n;
    nums[x]+=n;
}
for(i=0;i<n;i++){
    if(nums[i]<=n){
        missingList.add(i+1);
    }
}
return missingList;
    }
    }

复杂度分析:
时间复杂度:O(n),其中n是数组nums的长度
空间复杂度:O(1),返回值不计入空间复杂度

442.数组中重复的数据

题目:在这里插入图片描述

我的思路及解法:第一次自己做出了中等题,好有成就感,虽然这道中等难度的题应该是中等里面的下等,不过还是很开心哈哈哈哈,美中不足的就是没有符合题目中对空间复杂度的限制了。下面说一下我的思路。

题目中说每个整数出现一次或两次,那么也有一些整数是没有出现的。
设定:整数x在数组上的位置为nums[x-1],nums[x-1]的值正负表示该整数的出现频率。
定义一个跟原数组等长的新数组copyNums,遍历数组nums,取nums[i]的值的绝对值,寻找该整数在数组上的位置,令该位置上的值乘-1,并将其添加到数组中copyNums,若该位置再次被访问,则说明该元素出现了两次(再乘-1为正),更新其在copyNums中的值。
copyNums中,copyNums[j]大于0的表示整数(j+1)出现两次,小于0的表示出现1次,等于0的表示未出现。
遍历copyNums,取大于0的元素下标j+1,添加到res中,返回res
代码

class Solution {
    public List<Integer> findDuplicates(int[] nums) {
List<Integer> res=new ArrayList();
int n=nums.length;
int z=0;
int[] copyNums=new int[n];
for(int i=0;i<n;i++){           
     z=nums[i]>0?nums[i]-1:(-nums[i]-1);
    nums[z]=-nums[z];
    copyNums[z]=nums[z];
}
for(int j=0;j<n;j++){
    if(copyNums[j]>0){
        res.add(j+1);
    }
}
return res;
    }
}

复杂度分析
时间复杂度:O(n),n为原数组长度
空间复杂度:O(n),n为原数组长度


更优解法:使用正负号作为标记
思路及算法:在官方解答下找到了同样用正负号作为标记的解法,而且完美解决了空间复杂度O(n)的问题
在这里插入图片描述

代码:

class Solution {
    public List<Integer> findDuplicates(int[] nums) {
        int n = nums.length;
        List<Integer> ans = new ArrayList<Integer>();
        for (int i = 0; i < n; ++i) {
            int x = Math.abs(nums[i]);
            if (nums[x - 1] > 0) {
                nums[x - 1] = -nums[x - 1];
            } else {
                ans.add(x);
            }
        }
        return ans;
    }
}

复杂度分析:
时间复杂度:O(n),n为数组长度
空间复杂度:O(1)。

目前看到的最优解法:元素和数组长度进行比较
思路及算法:先遍历数组,每遍历一个数nums[i]就给数组中第nums[i]个数加上数组的长度值。例如[2,1,1],遍历完以后是[2+3+3,1+3,1]也就是[8,4,1]。这个8的出现是因为原数组有两个1,使得遍历后该数组第1个位置的值2加了两次3,所以答案就是1,所以只要知道数组中哪个位置的值大于两倍的数组长度,就知道该位置的顺序值是在数组中出现两次的。
而且这个方法对出现三次四次及以上次数的判断都是通用的,评论区第一的方法对出现奇数次的情况就不适用了。

代码:

class Solution {
    public List<Integer> findDuplicates(int[] nums) {
         int n=nums.length;
         for(int i=0;i<n;i++){
             nums[(nums[i]-1)%n]+=n;
             //System.out.print(nums[i]);
         }
        List<Integer> ret=new ArrayList<Integer>();
        for(int i=0;i<n;i++){
            if (nums[i]>2*n){
                ret.add(i+1);
            }
        }
        return ret;
    }
}

复杂度分析:
时间复杂度:O(n)
空间复杂度:O(1)

41.缺失的第一个正数

题目:在这里插入图片描述

我的思路及解法
由题可知,将数组进行排序之后,正常情况下数组的情况为[1…n]。
第一次遍历,取出第i个元素,若第i个元素的值与nums[nums[i]-1]不相同,则与原来该位置上的元素进行交换,交换过后继续对第i个位置上的元素进行判断。否则i++,继续遍历下一个位置上的元素。如果出现nums[i]>nums.length,nums[i]<=0,nums[i]=i+1(该情况说明该元素在正确的位置上)则i++,继续遍历下一个元素。
第一次遍历结束后,此时在[1…n]范围之内的每个元素都在他们的正确位置上了。如示例2经过第一次while遍历之后,nums[1,-1,3,4];
再次遍历,若出现nums[j]!=j+1,则return j+1。该值为没有出现的最小的正整数。
如果数组每个元素都存在[1,n]。则返回n+1
代码

class Solution {
    public int firstMissingPositive(int[] nums) {
 int n=nums.length;
 int i=0;
 int x=0;
 int j=0;
 while(i<n){
     if(nums[i]==i+1||nums[i]<=0||nums[i]>=n){
         i++;
         continue;
     }else{
         x=nums[i];
         if(x!=nums[x-1]){
nums[i]=nums[x-1];
nums[x-1]=x;
     }
     else{
         i++;
         continue;
     }
 }
 }
for(j=0;j<n;j++){
    if(nums[j]!=j+1){
        return j+1;
    }
}
   return j+1;
    }
}

复杂度分析
时间复杂度:O(n),n为数组的长度
空间复杂度:O(1)

274.H指数

题目:在这里插入图片描述

我的思路及解法
首先将初始的H指数的值h设为0,然后将引用次数排序,并且对排序后的数组从大到小遍历。
根据H指数的定义,如果当前H指数为h并且在遍历过程中找到当前值citations[i]>h,则说明我们找到了一篇被引用了至少h+1次的论文,所有将h值加1,继续遍历直到h无法继续增大,最后返回h作为最终答案。
代码

class Solution {
    public int hIndex(int[] citations) {
        Arrays.sort(citations);
        int h = 0, i = citations.length - 1; 
        while (i >= 0 && citations[i] > h) {
            h++; 
            i--;
        }
        return h;
    }
}

复杂度分析
时间复杂度:O(n logn),其中n为数组长度,即为排序的时间复杂度。
空间复杂度:O(logn),其中n为数组长度,即为排序的空间复杂度。

453.最小操作次数使数组元素相等

题目:

我的思路及解法
想了半天没想出来,一看官解我是shaX。。。
果然数学还是太差了,又学到了新知识,当求一件事件很难时,就想着求他的对立事件。
在这里插入图片描述

代码

class Solution {
    public int minMoves(int[] nums) {
        int minNum = Arrays.stream(nums).min().getAsInt();
        int res = 0;
        for (int num : nums) {
            res += num - minNum;
        }
        return res;
    }
}

作者:LeetCode-Solution
链接:https://leetcode.cn/problems/minimum-moves-to-equal-array-elements/solution/zui-xiao-cao-zuo-ci-shu-shi-shu-zu-yuan-3meg3/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

复杂度分析
时间复杂度:O(n),其中n为数组中的元素数量,我们需要一次遍历求出最小值,一次遍历计算操作次数。
空间复杂度:O(1)
更优解法:
思路及算法

代码:


复杂度分析:
时间复杂度:
空间复杂度:





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值