LeetCode热题100 【cpp】题解(一)哈希表和双指针

这篇具有很好参考价值的文章主要介绍了LeetCode热题100 【cpp】题解(一)哈希表和双指针。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

题单链接: LeetCode 热题 100

1. 两数之和

leetcode题目链接
题解1:暴力枚举
时间复杂度: O ( n 2 ) O(n^2) O(n2)

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        vector<int> v;
        for (int i = 0; i < nums.size() - 1; i ++) {
            for (int j = i + 1; j < nums.size(); j ++) {
                if (nums[i] + nums[j] == target) {
                    v.push_back(i), v.push_back(j);
                }
            }
        }
        return v;
    }
};

题解2:哈希表
时间复杂度: O ( n ) O(n) O(n)

使用hash表来存target - x的差值的下标。这里使用cpp里面的unordered_map,它的查找效率为 O ( 1 ) O(1) O(1)

补充unordered_map 查找key的方法:count(), 如果存在某个key, 返回1;如果不存在某个key,返回0.

class Solution {
public:
    vector<int> twoSum(vector<int>& nums, int target) {
        unordered_map<int, int> heap; // heap存 <差值, 下标>
        for (int i = 0; i < nums.size(); i ++) {
            int r = target - nums[i];
            if (heap.count(r)) { // count方法判断key存不存在
                return {heap[r], i};
            }
            heap[nums[i]] = i; // 记录这个数的下标
        }
        return {};
    }
};

49. 字母异位词分组

leetcode题目链接

题解:
字母异位词的意思是某些字符串含有相同的字母,并且每个字母出现的次数相同。字母异位词也可以理解为字符串排完序之后完全相同。

本题解利用后者(排序)进行处理:如果两个字符串是字母异位词,那么它们排完序之后一定相同。可以使用哈希表来维护一个string的vector,记录排完序相同的字符串。时间瓶颈是在排序上,排序的复杂度是 n l o g n nlogn nlogn
时间复杂度: O ( n l o g n ) O(nlogn) O(nlogn)

class Solution {
public:
    vector<vector<string>> groupAnagrams(vector<string>& strs) {
        unordered_map<string, vector<string>> hash;
        for(auto& str: strs) {
            string nstr = str; // nstr为排序过后的新字符串
            sort(nstr.begin(), nstr.end());
            hash[nstr].push_back(str);
        }

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

128. 最长连续序列

leetcode题目链接

题解:哈希表
我们每次从一个序列的最小值开始枚举,如果是连续的,迭代器不停++。比如最小值是x,那么其后是x+1, x+2, …, y,那么该连续序列的长度是多少呢?是y - x +1 这么长。为了加快查找速度,我们将所有元素存入哈希表unordered_set S中。还有一个问题,如何确定一个序列的开始呢? 如果哈希表S中存在x,不存在x - 1,那么我们就说x是一个序列的开始。

补充
unordered_set这个hash表,会将元素去重,并且不会排序,可以通过元素的值快速检索出该元素。
时间复杂度: O ( n ) O(n) O(n)

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        unordered_set<int> S;
        // 构造hash表:将所有元素插入到set中
        for(auto x: nums) S.insert(x);
        
        int res = 0;
        for(auto x : S) {
            // 枚举序列的最小值x
            if(S.count(x) && !S.count(x - 1)) {
                int y = x;
                // 如果是连续的序列,y一直++
                while(S.count(y + 1)) {
                    y ++;
                }
                res = max(res, y - x + 1); // 更新序列长度
            }
        }
        return res;
    }
};

283. 移动零

leetcode题目链接
题解:双指针

前一个指针x从头开始遍历数组,后一个指针k保存非零元素,k从零开始,逐渐加1。当所有的非零元素都移动到前面之后,此时k指向第一个零的位置,从此往后枚举补零即可。

时间复杂度: O ( n ) O(n) O(n)

class Solution {
public:
    void moveZeroes(vector<int>& nums) {
        int k = 0; // k是后一个指针,用于存放非零的数
        for (auto x : nums) {
            if (x) {
                nums[k] = x;
                k ++;
            }
        }
        // 把数组后面的位置补零
        while (k < nums.size()) {
            nums[k] = 0;
            k ++;
        }
    }
};

11. 盛最多水的容器

leetcode题目链接
题解:双指针
两个指针i 和 j形成的水槽的面积由短板决定,面积计算公式如下:
S = m i n ( h [ i ] , h [ j ] ) ∗ ( j − i ) S = min(h[i], h[j]) * (j - i) S=min(h[i],h[j])(ji)

每个状态下,两个指针i和j向中间移动一格,都会使得底边变短,怎样才能使得面积变大呢?
只有每次把短板向中间靠拢,它向中间靠拢才可能使矩形的高变高,面积才能变大。因为下一个状态的高度可能比短板高。移动的过程中,每次记录下来面积的最大值。参考 leetcode题解

时间复杂度: O ( n ) O(n) O(n)

class Solution {
public:
    int maxArea(vector<int>& height) {
        int res = 0;
        for (int i = 0, j = height.size() - 1; i < j;) {
            res = max(res, min(height[i], height[j]) * (j - i));
            // 每次短边向中间移动
            if (height[i] < height[j]) i ++;
            else j --;
        }
        return res;
    }
};

15. 三数之和

leetcode题目链接

题解:排序 + 双指针

对数组从小到大排序。开始遍历数组,第一个下标 i i i 表示三个数中的第一个,我们固定这个数,然后使用双指针算法(枚举 j 和 k j和k jk)找到另外两个数,使得 n u m s [ i ] + n u m s [ j ] + n u m s [ k ] ≥ 0 , i < j < k nums[i] + nums[j] + nums[k] \ge 0, i < j < k nums[i]+nums[j]+nums[k]0,i<j<k,同时使得k尽可能的小(k是最后一个指针,指向三数中的最大值,从右往左移动)。在上述情况中找到三数之和等于0的情况。

另外,需要确保没有枚举出来重复的情况,比如 n u m s = [ − 1 , − 1 , − 1 , − 1 , 2 ] nums = [-1, -1, -1, -1, 2] nums=[1,1,1,1,2],怎样才能做到只出现一次 [ − 1 , − 1 , 2 ] [-1, -1, 2] [1,1,2]?在枚举的时候如果出现 n u m s [ i ] = = n u m s [ i − 1 ] nums[i] == nums[i-1] nums[i]==nums[i1],我们就跳过,直接 i i i++, 直到 n u m s [ i ] ≠ n u m s [ i − 1 ] nums[i] \ne nums[i-1] nums[i]=nums[i1] n u m s [ j ] nums[j] nums[j]同理。

时间复杂度: O ( n 2 ) O(n^2) O(n2),排序是 O ( n l o g n ) , O(nlogn), O(nlogn), 外层循环 ( i ) (i) i O ( n ) O(n) O(n), 内层双指针循环 j 和 k j 和 k jk O ( n ) O(n) O(n),相乘是 O ( n 2 ) O(n^2) O(n2)

参考题解:acwing题解

class Solution {
public:
    vector<vector<int>> threeSum(vector<int>& nums) {
        vector<vector<int>> res;
        if (nums.size() < 3) return res;
        sort(nums.begin(), nums.end());

        for (int i = 0; i < nums.size(); i ++) {
            if (i > 0 && nums[i] == nums[i - 1]) continue;
			// 双指针:j是头指针,k是尾指针,两者向中间靠拢
            for (int j = i + 1, k = nums.size() - 1; j < k; j ++) {
                if (j > i + 1 && nums[j] == nums[j - 1]) continue;
                // 找到3数之和 ≥ 0 的最小的位置, k是3数之和≥0的最前面的位置
                while (j < k - 1 && nums[i] + nums[j] + nums[k - 1] >= 0) k --;

                if (nums[i] + nums[j] + nums[k] == 0)
                    res.push_back({nums[i], nums[j], nums[k]});
            }
        }

        return res;
    }
};

42. 接雨水

leetcode题目链接

题解:双指针,计算总面积 - 陆地面积。计算总面积时是每行的面积进行累加。
数组求和使用cpp中的accumulate函数。
参考题解:接雨水文章来源地址https://www.toymoban.com/news/detail-700755.html

class Solution {
public:
    int trap(vector<int>& height) {
        int length = height.size();
        if (length < 3) return 0;
        int l = 0, r = length - 1;
        // 前一次计算时的高度
        int preHeight = 0;
        // 陆地 + 雨水的总面积
        int totalArea = 0;
        // 陆地面积:数组所有数求和
        int landArea = 0;
        // accumulate 是cpp累加函数
        landArea = accumulate(height.begin(), height.end(), 0);

        while (l < r) {
            while (l < r && height[l] <= preHeight) l ++;
            while(l < r && height[r] <= preHeight) r --;

            // 每一层的面积:高度差 x 宽度
            totalArea += (min(height[l], height[r]) - preHeight) * (r - l + 1);

            preHeight = min(height[l], height[r]);
        }

        return totalArea - landArea;
    }
};

到了这里,关于LeetCode热题100 【cpp】题解(一)哈希表和双指针的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • LeetCode热题100——图论

    给你一个由 ‘1’(陆地)和 ‘0’(水)组成的的二维网格,请你计算网格中岛屿的数量。岛屿总是被水包围,并且每座岛屿只能由水平方向和/或竖直方向上相邻的陆地连接形成。 输入:grid = [ [“1”,“1”,“1”,“1”,“0”], [“1”,“1”,“0”,“1”,“0”], [“1”,“1”

    2024年01月16日
    浏览(76)
  • LeetCode 热题 HOT 100

    重点是当有一个链表为空了不单独处理,按节点为0处理。 滑动窗口! 首先要判断slow需不需要更新,怎么判断?slow = max(umap[s[fast]], slow);什么意思,就是说:**umap[s[fast]]的意义是,为了在slow和fast之间不出现重复字符,slow能处于的最左位置。**如图,当j第一次到d,将umap[s[j

    2024年02月07日
    浏览(47)
  • LeetCode热题100——链表

    给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回

    2024年02月05日
    浏览(43)
  • LeetCode 热题 100 | 链表(上)

    目录 1  基础知识 1.1  空指针 1.2  结构体 1.3  指针访问 1.4  三目运算符 2  160. 相交链表 3  206. 反转链表 4  234. 回文链表 菜鸟做题第三周,语言是 C++ 1  基础知识 1.1  空指针 使用 nullptr 来判断是否为空指针: “NULL 在 C++ 中就是 0,这是因为在 C++ 中 void* 类型是不允许隐式

    2024年02月19日
    浏览(41)
  • LeetCode热题 100整理

    35. 搜索插入位置 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums = [1,3,5,6], target = 5 输出: 2 示例 2: 输入: nums = [1,3,5,6], target

    2024年02月13日
    浏览(38)
  • LeetCode 热题100——单调栈

    ​   个人主页: 日刷百题 系列专栏 : 〖C语言小游戏〗 〖Linux〗 〖数据结构〗   〖C语言〗 🌎 欢迎各位 → 点赞 👍+ 收藏 ⭐️+ 留言 📝  ​ ​ 递增单调栈:栈中元素从栈底到栈顶依次增大 递减单调栈:栈中元素从栈底到栈顶依次减小 在学习完朴素的数据结构栈之后,

    2024年02月04日
    浏览(41)
  • Leetcode热题100

    暴力:{i,j}直接返回vectorint 哈希表: map: 红黑树 具有自动排序的功能,是非严格的二叉搜索树。map内部的所有元素都是有序的,使用中序遍历可将键值按照从小到大遍历出来。插入的时间是O(logn),查询时间是O(logn)。可以支持所有类型的键值对 unordered_map: 哈希表(也叫散列表

    2024年02月14日
    浏览(52)
  • 【LeetCode热题100】【矩阵】螺旋矩阵

    题目链接:54. 螺旋矩阵 - 力扣(LeetCode) 先走外面的圈再走里面的圈,可以用递归来解决,对于要走的一个圈,由四个角决定,其实是三个数,(0,0),(0,n),(m,0),(m,n),每次先从左上角走到右上角,再走到右下角,再走到左下角,再走回来 对于后面两个的往

    2024年04月16日
    浏览(40)
  • LeetCode 热题100——链表专题

    2.俩数相加(题目链接) 思路:这题题目首先要看懂,以示例1为例  即  342+465=807,而产生的新链表为7-0-8. 可以看成简单的从左向右,低位到高位的加法运算,4+6=10,逢10进1,新链表第三位为3+4+1(第二位进的1),需要注意的的点是当9-9-9和9-9-9-9相加,相当于9-9-9-0和9-9-9-9相加

    2024年02月05日
    浏览(36)
  • LeetCode 热题 100 | 动态规划(一)

    目录 1  70. 爬楼梯 1.1  基本思路 1.2  官方题解 2  118. 杨辉三角 3  198. 打家劫舍 菜鸟做题,语言是 C++ 1  70. 爬楼梯 核心思想:把总问题拆解为若干子问题。 总问题:上到 5 楼的方式有多少种 子问题:上到 4 楼的方式有多少种、上到 3 楼的方式有多少种 总问题 = 子问题 1

    2024年04月17日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包