【leetcode hot 100】刷题记录与总结笔记(4/100)

(•̀ᴗ•́)و 大二打算法的小菜狗又回来啦!这次是以研究生找工作的目标开始刷题,坚持就是胜利!每天一道,完成比完美更加重要!

这篇笔记会使用Java和C++两种语言去刷题~

目录

[1、两数之和 - 哈希表](#1、两数之和 - 哈希表)

[2、字母异位词分组 - 哈希表](#2、字母异位词分组 - 哈希表)

[3、最长连续序列 - 哈希表](#3、最长连续序列 - 哈希表)

[4、移动零 - 双指针](#4、移动零 - 双指针)


1、两数之和 - 哈希表

这道题很容易想到O(n2)的双for循环暴力破解,这里就不再赘述。
思路

每遍历到一个位置,开始查map:前面有没有人和我匹配?有就直接返回,没有就把自己登记到map中,继续往后寻找

用Map存【numsi : 下标i】,注意值为key,下标为value

这样遍历数组nums时,对于每一个numsi

  • 如果map中存在key = target - numsi,说明当前数和前面的某个数之和恰好为target,直接返回map(target-nums\[i)下标,i]
  • 否则将【numsi:i】存入map中,继续向后寻找

【1】Java版

java 复制代码
class Solution {
    public int[] twoSum(int[] nums, int target) {
        Map<Integer,Integer> mp = new HashMap<>();

        for(int i = 0;i < nums.length; i++){
            if(mp.containsKey(target - nums[i])) 
               return new int[]{mp.get(target - nums[i]),i};
            mp.put(nums[i],i);
        }
        throw new IllegalArgumentException("No two sum solution");
    }
}

【2】C++版

cpp 复制代码
class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int,int> mp;
        for(int i=0;i<nums.size();i++){
            if(mp.count(target - nums[i]))
                return {mp[target - nums[i]],i};
            mp[nums[i]]=i;
        }
        return {};
    }
};

2、字母异位词分组 - 哈希表

题意

如果两个字符串从小到大排序后相等,那么两个字符串就互为字母异位词,否则不是。

例如 aab,aba,baa 排序后都是 aab,所以 aab,aba,baa 互为字母异位词。
思路

用哈希表存储【key:排序后的字符串,value列表:排序前的字符串】

最后按key输出每组value值

【1】Java版

cpp 复制代码
class Solution {
    public List<List<String>> groupAnagrams(String[] strs) {
        Map<String,List<String>> mp = new HashMap<>();

        for(String s : strs){
            char[] sorted = s.toCharArray();
            Arrays.sort(sorted);
        //- 如果map中不存在这个key,则创建一个新的空List作为value
        //- 如果map中已存在这个key,则直接返回对应的value(已有的List)
        //最后,将字符串s添加到这个(新的或已有的)List中
            mp.computeIfAbsent(new String(sorted),_ -> new ArrayList<>()).add(s);
        }
        return new ArrayList<>(mp.values());
    }
}

【2】C++版

cpp 复制代码
class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string,vector<string>> mp;

        for(string& s:strs){
            string sorted = s;
            sort(sorted.begin(),sorted.end());
            mp[sorted].push_back(s);
        }

        vector<vector<string>> res;
        for (auto& pair : mp) {
            res.push_back(pair.second);
        }
        return res;
    }
};

3、最长连续序列 - 哈希表

我尝试排序sort,只跑通一半样例,想【0,1,1,2】这种情况最长序列个数为3(0,1,1)或(1,1,2),但我的代码计算这个样例时跑出来是(0,1,1,2),故放弃,看题解


题意

给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

请你设计并实现时间复杂度为 O(n) 的算法解决此问题。

0,1,1,2 答案:3
思路

首先,本题是不能排序的,因为排序的时间复杂度是 O(nlogn),不符合题目 O(n) 的要求。

我们将数字存入set(去重),因为set可以快速判断元素是否存在set.contains()

核心思路:对于 nums 中的元素 x,以 x 为起点,不断查找下一个数 x+1,x+2,⋯ 是否在 nums 中,并统计序列的长度。

  • 我们遍历set中的每一个元素x,对于每一个x,如果set中存在x-1,则跳过该x,因为后面以x-1为起点的序列肯定更长,避免重复计算
  • 确定好起点x后,循环向后不断查找 y = x+1 是否在set中,如果存在则y++
  • 循环结束后,y-1就是连续序列的最后一个数,则最长序列为【x ~ y-1】,长度为 y-x
  • 遍历每一个x都以其为起点(如果存在更小的以更小的为起点,避免重复计算),算出以它为起点的最长连续序列长度,最后通过res = max(res , y-x)维护全场最长序列长度

【1】Java版

cpp 复制代码
class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> st = new HashSet<>();
        for(int num: nums) st.add(num);

        int res = 0;
        for(int x: st){
            if(st.contains(x - 1)) continue;

            int y = x + 1;
            while(st.contains(y)) y++;
            res = Math.max(res, y - x);
        }
        return res;
    }
}

【2】C++版

cpp 复制代码
class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        int res = 0;
        unordered_set<int> st(nums.begin(),nums.end());
        for(int x: st){
            if(st.contains(x-1)) continue;//如果序列中存在更小的,以更小的为起点
            //找到最小的起点x
            int y = x + 1;
            while(st.contains(y)) y++; //不断向后查找下一个数是否在set
            //循环结束后,y-1是最后一个在哈希表的数
            res = max(res, y - x); //从x~y-1序列长度为y-x
        }
        return res;
    }
};

4、移动零 - 双指针

题意:

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。请注意 ,必须在不复制数组的情况下原地对数组进行操作。

复制代码
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

思路:

最直接的思路是,把非零元素整体挪到最前面,零元素整体挪到最后面

我们可以维护下标【i0 ~ i-1】区间为零元素,ai0始终指向最靠左边的零元素

  • 当i=n时循环结束,此时【i0 ~ n-1】即为零元素,即把零元素挪到最后
  • :这里ai0始终在最左边,这样非零元素和ai0交换时始终在相对最前边,即保证非零元素原始顺序

遍历数组a,如果:

  • ai=0,则不操作
  • ai≠0,则交换swap(ai,ai0),i0++

比如0,1,0,3,12:(绿色区间代表维护的【i0 ~ i-1】区间)

i=0 ++0++,1,0,3,12 不操作 i0=0

i=1 0,++1++,0,3,12 swap(ai=1,ai0=0) i0++(i0=1)

i=1 ++1,0++,0,3,12 交换完

i=2 1,0,++0++,3,12 不操作 i0=1

i=3 1,0,0,++3++,12 swap(ai=3,ai0=0) i0++(i0=2)

i=3 1,++3++ ,0,++0++,12 交换完

i=4 1,3,0,0,++12++ swap(ai=12,ai0=0) i0++(i0=3)

i=4 1,3,++12++,0,++0++ 交换完

i=5 1,3,12,0,0 遍历结束(i0=3)

【1】Java版

cpp 复制代码
class Solution {
    public void moveZeroes(int[] a) {
        int i0=0;
        for(int i=0;i<a.length;i++)
            if(a[i]!=0)
            {
                int t=a[i];
                a[i]=a[i0];
                a[i0]=t;
                i0++;
            }
        
    }
}

【2】C++版

cpp 复制代码
class Solution {
public:
    void moveZeroes(vector<int>& a) {
        int i0 = 0;
        for(int i = 0; i < a.size(); i++){
            if(a[i]!=0){
                swap(a[i],a[i0]);
                i0++;
            }
        }
    }
};
相关推荐
小羊在睡觉1 小时前
力扣84. 柱状图中最大的矩形
后端·算法·leetcode·golang·go
3DVisionary1 小时前
蓝光三维扫描:医疗制造的精度焦虑怎么解
人工智能·算法·制造·蓝光三维扫描·医疗制造·三维检测·义齿检测
好评笔记1 小时前
机器学习面试八股——常用损失函数
人工智能·深度学习·算法·机器学习·校招
weixin_468466851 小时前
全局与局部注意力机制新手实战指南
人工智能·python·深度学习·算法·自然语言处理·transformer·注意力机制
sheeta19982 小时前
LeetCode 每日一题笔记 日期:2026.05.29 题目:3300. 最小元素
笔记·leetcode
_日拱一卒2 小时前
LeetCode:994腐烂的橘子
java·数据结构·算法·leetcode·深度优先
中屹指纹浏览器2 小时前
2026指纹浏览器代理链路适配原理与多线路集群调度方案
经验分享·笔记
珂朵莉MM2 小时前
第七届全球校园人工智能算法精英大赛-算法巅峰赛产业命题赛第3赛季优化题--束搜索
人工智能·算法
不羁的木木2 小时前
ArkWeb实战学习笔记05-综合实战:构建混合应用
笔记·学习·harmonyos
CC大煊3 小时前
一个Javaer的AI转型笔记(1):入坑LangChain,我的第一个hello world
笔记·langchain