LeetCode热题100(2)

【Leetcode 力扣热题100 #2 字母异位词分组】 创建给定字符串数组同样大大小的布尔数组用作标记,标记已归类的项,在外层循环中逐个检查未被标记的字符串在内层循环中进行比对,对每个未标记的字符串,再次遍历后续所有字符串,通过排序比较字符是否相同(异位词),最后将匹配的异位词标记为已处理,归入同一分组。题目说明给定的每个字符串数组中的字符串只包含26个小写字母,所以用一个长度为26的数组统计各字母出现的次数,替代更高时间复杂度的排序法。对每个字符串排序后的字符数组作为哈希表的键,将相同键的字符串存入哈希表对应的列表中,最后直接返回哈希表中所有值列表的集合。 阅读详情

42. 接雨水

1、题解

这道题其实就是需要我们计算出每一个柱子可以最多盛多少水,然后把它们相加。

以示例二为例,我要算出下标 2 这个位置可以盛多少雨水,是不是需要往下标 2 的左边看看找到最大高度 4 ,然后往下标 2 的右边看看找到最大高度 5 ,而盛水多少是取决于,两个高度较小的那个,选高的那个高度绝对溢出,那这个地方就要选择下标 0 ,然后再用 height [0] 减去下标2 位置的高度就可以得出结果了。
这里把 i 下标左边的最大高度设置为 mleft[i],i 下标右边的最大高度设置为 mright[i],盛水多少 = max(mleft[i], mright[i])- height[i]。

(1)暴力算法,遍历所有下标,每次都从左边找最大高度,从右边找到最大高度,时间复杂度就是O(N2)。
(2)动态规划的思想:我们可以利用两个数组,分别记录i位置的左边最大高度
  = max (mleft[i-1], height[i-1]),右边最大高度 = max (mright[i+1], height[i+1])
,最后再遍历一次数组,根据盛水多少 = max(mleft[i], mright[i])- height[i] ,然后累加,不就可以得出最后结果了吗。其实就是用空间换时间的思想。

class Solution {
public:
    int trap(vector<int>& height) {
        //利用两个数组,分别记录i位置的左边最大高度=max(mleft[i-1],height[i-1]),
        //右边最大高度=max(mright[i+1],height[i+1])
        int n = height.size();
        vector<int> mleft(n), mright(n);
        for(int i = 1; i < n; i++)
        {
            mleft[i] = max(mleft[i-1], height[i-1]);
        }
        for(int i = n-2; i >= 0; i--)
        {
            mright[i] = max(mright[i+1], height[i+1]);
        }
        //每一个位置的盛水高度:min(mleft[i], mright[i]) - height[i]
        int ret = 0;
        for(int i = 0; i < n; i++)
        {
            int tmp = min(mleft[i], mright[i]) - height[i];
            if(tmp > 0) ret += tmp;
        }
        return ret;
    }
};

(3)双指针

我们可以利用“短板”,什么意思呢?我们可以设置几个变量,maxleft 为 left 左边的最大高度,maxright 为 right 右边的最大高度,当我利用 left 和 right 进行遍历时,可以通过比较 maxleft 和 maxright 更新 left 或 right 位置的雨水存储。
按照上图,当 maxleft < maxright 时,是不是 left 位置的短板就一定是 maxleft 了,因为你 maxleft已经是小的一方了,你在 left 左边再怎么找比 maxleft 或者 maxright 大的都无济于事了,因为短的那一方决定了盛雨水的多少,此时就可以通过 maxleft - height[left] 得到盛的雨水量,然后再让left++对不对?不是,你要先更新 maxleft = max(maxleft , height[left]) 才能让 left++。
同理,如果 maxleft > maxright 时,是不是 right 位置的短板就一定是 maxright,通过 maxright - height[right] 得到盛的雨水量,更新 maxright = max(maxright , height[right]) 才能让 right--。
如果 maxleft == maxright,更新谁都可以;这里注意循环条件应该是 left <= right,因为进入循环时,我们是通过比较决定统计谁的雨水量,那说明统计前left 和 right 都是没有被统计的,如果仅仅是 left < right,最后肯定有一个位置的雨水一定没有被统计。

class Solution {
public:
    int trap(vector<int>& height) {
        //利用短板,使用双指针
        int n = height.size();
        //maxleft: left左边的最大高度
        //maxright: right右边的最大高度
        int maxleft = height[0], maxright = height[n-1];
        int left = 1, right = n - 2;//因为左右两端不可能有雨水
        int ret = 0;
        while(left <= right)
        {
            //left和right雨水还没有统计
            //思想:统计left还是right位置的雨水,取决于min(maxleft, maxright)
            if(maxleft < maxright)
            {
                //更新left位置,左边的maxleft已经是短板了,右边即使有比当前maxright更大的高度
                //也没有用,left位置的雨水已经可以统计了
                //为什么不更新right位置的雨水,因为短板不确定
                //:在left到right-1的区间可能存在比maxright或者比maxleft小的高度
                int tmp = maxleft - height[left];
                if(tmp > 0) ret += tmp;
                //更新maxleft
                maxleft = max(maxleft, height[left++]);
            }
            else
            {
                int tmp = maxright - height[right];
                if(tmp > 0) ret += tmp;
                //更新maxleft
                maxright = max(maxright, height[right--]);
            }
        }
        return ret;
    }
};

438. 找到字符串中所有字母异位词

1、题解

这道题首先要搞懂什么是异位词,根据示例只要 s 的某个子串的大小等于 p ,并且字符个数一一对应,不需要一样顺序,就可以成立,并且返回 s 子串索引。

(1)直接暴力解法,遍历字符串 s ,每次都选取p.size() 个大小,可以通过hash表和 p 进行比较,这样的算法复杂度是O(N2)
(2)滑动窗口:我们在比较完 "cba" 后其实不用再从 b 开始往后遍历,你会发现下一次比较选取的是子串 "bae" ,对比之前的子串,是不是就是少了一个"c",多了一个"e",所以我们完全可以每次都只加入一个字符,去除最左边的字符;然后只要窗口大小(right - left + 1)和 p.size() 相等,就可以对两个字符数组进行比较。
(3)比较方式:因为题目说了字符都是在 a~z ,直接用两个数组hash[26]统计两个被比较的字符串的个数:hash[字符-‘a’]++,最后只需要循环26次,判断两个hash对应字符个数是否一样即可。
但是如果题目不是字符都是在 a~z那怎么办,我们可以通过一个变量count-->统计字符有效个数。

什么意思呢?遍历 s 字符串时,字符 c 进窗口后,hashs中 c 的个数 <= hashp 中 c 的个数,那么滑动窗口中对于p,是不是有效个数应该+1;而第二个字符 c 进入窗口后,hashs中 c 的个数变成2了,我们就不应该让有效字符个数+1,因为这个 c 对于字符串 p 是多余的;所以当 right 走到 b 位置,进窗口后判断是否是字母异位词时,就不需要通过循环26次判断两个字符串是否一致了,直接通过count == 2判断条件不成立。
当 right 走到 a 位置,进窗口后发现滑动窗口个数为4了,就要出窗口,那我在把第一个 c 出窗口后,hashs中 c 的个数变成 1 ,正好和 hashp中 c 的个数对应,count没必要--,只有当出窗口后,left 位置的 hashs[s[left] - 'a'] < hashp[s[left] - 'a'],count才要 - 1。

下面两个比较方法都给出:
(1)循环26次比较

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> ret;
        int left = 0, right = 0;
        int hashp[26] = {0}, hashs[26] = {0};
        for (int i = 0; i < p.size(); i++) {
            hashp[p[i] - 'a']++;
        }
        while (right < s.size()) {
            // 进窗口
            hashs[s[right] - 'a']++;
            // 判断
            if (right - left + 1 > p.size()) {
                hashs[s[left] - 'a']--; // 出窗口
                left++;
            }
            if (right - left + 1 == p.size()) {
                // 更新结果:比较两个hash表
                int flag = 0;
                for (int i = 0; i < 26; i++) {
                    if (hashp[i] != hashs[i])
                        flag = 1;
                }
                if (flag == 0)
                    ret.push_back(left);
            }
            right++;
        }
        return ret;
    }
};

(2)通过有效字符个数count

class Solution {
public:
    vector<int> findAnagrams(string s, string p) {
        vector<int> ret;
        int left = 0, right = 0;
        int hashp[26] = {0}, hashs[26] = {0};
        for (int i = 0; i < p.size(); i++) {
            hashp[p[i] - 'a']++;
        }
        int count = 0;//统计有效字符
        while (right < s.size()) {
            // 进窗口
            hashs[s[right] - 'a']++;

            if(hashs[s[right] - 'a'] <= hashp[s[right] - 'a']) count++;

            // 判断
            if (right - left + 1 > p.size()) {
                hashs[s[left] - 'a']--; // 出窗口

                if(hashs[s[left] - 'a'] < hashp[s[left] - 'a']) count--;

                left++;
            }
            if(count == p.size()) ret.push_back(left);
            right++;
        }
        return ret;
    }
};

面试题 16.25. LRU 缓存

1、题解:示例1先是插入(1,1),再插入(2,2),当get(1)后,再插入(3,3)时,发现淘汰的是(2,2),说明不管是查找元素还是插入元素,都要让这个元素成为最近使用的。如果说只想到单链表,把访问的元素移到头结点,或者插入新元素时加在头结点,那么会有两个问题:
(1)查找节点时,时间复杂度是O(N)
(2)淘汰最近最久未被使用的节点时也需要对链表进行遍历
改进办法:使用 unordered_map,保存节点的<key,链表节点>,可以使查找时间复杂度到O(1),那为什么要把“链表节点”当成value 呢?主要是为了在访问节点后,需要把这个节点移到链表头,保持它是最近被使用的状态,实现移动节点也是O(1)的复杂度。

只有单向链表是不够的,因为在淘汰最近最久未被使用的节点时,我也不知道这个节点的 key 值,没办法利用哈希表来找到对应节点指针;既然要淘汰的节点肯定是链表最后一个节点,那我使用双向链表,维护一个尾指针,不保存有效数据,只为了在淘汰最后一个有效节点时通过 tail->prev找到它。而无效数据的头结点和尾节点也可以减少判空问题。

这里的代码实现涉及到某个结点移动时或者删除时,它的前驱节点和后继节点的指向关系,通过画图理解就可以实现;还有一点就是插入新节点时(key,value),如果这个key已经存在,那我就把value的值覆盖即可,记得不管是查找get,还是put都要把对应节点移动到链表第一个有效节点的位置。

struct Node
{
    int key;
    int value;
    Node* prev;
    Node* next;
    Node(int k, int v):key(k), value(v)
    {
        prev = nullptr;
        next = nullptr;
    }
};

class LRUCache {
    unordered_map<int, Node*> map;
    Node* _head;
    Node* _tail;
    int _capacity;
    int _size;
public:
    LRUCache(int capacity) {
        _capacity = capacity;
        _size = 0;
        //记得先new
        _head = new Node(-1,-1);
        _tail = new Node(-1,-1);
        _head->next = _tail;
        _tail->prev = _head;
    }
    
    int get(int key) {
        if(map.count(key) == 0) return -1;
        Node* node = map[key];
        Remove(node);
        AddFront(node);
        return node->value;
    }
    
    void put(int key, int value) {
        if(map.count(key) == 1)//key存在,更新值,并且更新链表状态
        {
            Node* node = map[key];
            Remove(node);
            AddFront(node);
            node->value = value;
            return;
        }
        if(map.count(key) == 0)//key不存在,插入链表,更新状态
        {
            Node* node = new Node(key, value);
            map[key] = node;
            AddFront(node);
        }
        if(_size > _capacity)
        {
            map.erase(_tail->prev->key);//必须先删除hash表的node指针
            PopBack();//再释放链表节点
        }
    }

    void AddFront(Node* node)
    {
        Node* tmp = _head->next;
        _head->next = node;
        node->prev = _head;
        node->next = tmp;
        tmp->prev = node;
        _size++;
    }
    void Remove(Node* node)
    {
        Node* pre = node->prev;
        Node* nex = node->next;
        pre->next = nex;
        nex->prev = pre;
        _size--;
    }
    void PopBack()
    {
        Node* back = _tail->prev;
        back->prev->next = _tail;
        _tail->prev = back->prev;
        delete back;
        back = nullptr;
        _size--;
    }
};

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache* obj = new LRUCache(capacity);
 * int param_1 = obj->get(key);
 * obj->put(key,value);
 */

解决Calibre中license的错误 本次解决了Calibre在Cadence 617 virtuoso版本中运行不了的错误,在遇到问题的时候,我也跟你们一样,首先是上网查询为什么运行不了呢?明明我安装了之后里面有Calibre的,我当时也是这样的疑惑,一点Calibre运行LVS的时候,一片空白,然后就出现了license的错误,后来点点点,看看看,搜搜搜,最终解决了这个问题。虚拟机是VMware16版本,cadence617,Calibre是2015版本。旨在记录遇到的实际问题。 阅读详情

相关推荐

【阿里云大模型高级工程师ACP习题集】2.5 优化RAG应用提升问答准确度(⭐️⭐️⭐️ 重点章节!!!)

【摘要】这是我精心整理出对应的习题集,里面足足有 30 道题目,从基础概念到深度拓展,全方位覆盖章节重点、难点。不管你是想检验自己的学习成果,还是想针对薄弱环节进行强化训练,它都能完美适配!

davidkorhenn的博客 1105

LeetCode 热题 2/100打卡

【代码】LeetCode 热题 49/100打卡。

Rhett_Butler0922的博客 348

PyTorch GPU版本安装避坑指南:解决RuntimeError: No CUDA GPUs are available报错

本文详细解析了PyTorch GPU版本安装过程中常见的`RuntimeError: No CUDA GPUs are available`报错问题,从硬件驱动检查、CUDA Toolkit与cuDNN安装到PyTorch GPU版本的正确配置,提供了全面的避坑指南和实战验证方法,帮助开发者高效搭建深度学习开发环境。

r2s3t4的博客 296

第9题 力扣LeetCode 热题 HOT 100(2. 两数相加)

第9题 力扣LeetCode 热题 HOT 100(2. 两数相加) 给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。 请你将两个数相加,并以相同形式返回一个表示和的链表。 你可以假设除了数字 0 之外,这两个数都不会以 0 开头。 示例1: 输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8] 解释:342 + 465 = 807. 示例 2: 输入:l1 = [0], l2 = [0] 输出:[0]

weixin_45440200的博客 174

时间序列:R语言ARMA-GARCH模型

ARMA: #读入数据,并绘制时序图 d<-read.table("C:/Users/haha/Desktop/R/zuoye/1.txt") x<-ts(log(d),start = 1) 1: x的时间序列图: x<-ts(log(d),start = 1) plot(x) 2: 从上图可以看出x.dif序列值在0的附近波动,没...

1万+

STM32 USB AUDIO实战指南——从零构建音频设备

本文详细介绍了如何使用STM32F407构建USB音频设备,从硬件准备到软件配置,再到音频播放和录制功能的实现。通过STM32CubeMX配置和实战代码示例,帮助开发者快速掌握USB Audio Class规范,实现低延迟、高质量的音频传输,适用于语音交互、音乐播放等多种场景。

weixin_42549037的博客 484

力扣热题100--day2

42-接雨水不会,看了双指针的解法。

weixin_58753945的博客 1791

银河麒麟系统V10 Server SP1 安装Oracle 19c

•oracle-database-preinstall-19c 这个工具会自动配置系统参数,创建 oracle 用户和组。比较方便。•••••银河麒麟高级服务器操作系统V10 - 国产操作系统、银河麒麟、中标麒麟、开放麒麟、星光麒麟——麒麟软件官方网站。

fuguimashu的博客 4321

LeetCode 热题100 2. 两数相加

LeetCode 热题100 | 2. 两数相加

m0_63951116的博客 459

1、vectorCast单元测试常用操作

进入软件主页面,点击file,选择set working directory,随便选择一个保存该项目的目录即可。

weixin_59334478的博客 2156

5G/NR SSB学习总结

6.1 SSB概念 同步信号和PBCH块(Synchronization Signal and PBCH block, 简称SSB),它由主同步信号(Primary Synchronization Signals, 简称PSS)、辅同步信号(Secondary Synchronization Signals, 简称SSS)、PBCH三部分共同组成。 6.2 SSB特征 ...

欢迎来到小七的博客,这里将带你深入探索5G通信的神秘世界。无论你是通信领域的专业人士还是对这一领域充满好奇心的技术爱好者,这里都有专业协议解读、通信知识普及以及有趣的Python编程内容等你发现。 8万+

第2题 力扣LeetCode 热题 HOT 100 (581. 最短无序连续子数组)

第2题 力扣LeetCode 热题 HOT 100 (581. 最短无序连续子数组) 题目 给你一个整数数组 nums ,你需要找出一个 连续子数组 ,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。 请你找出符合题意的 最短 子数组,并输出它的长度。 示例 1: 输入:nums = [2,6,4,8,10,9,15] 输出:5 解释:你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。 示例 2: 输入:nums = [1,2,3,4] 输出:0 示例

weixin_45440200的博客 332

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

Python3—LeetCode 力扣热题100-2.字母异位词

给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。示例 1:输入: strs = ["eat", "tea", "tan", "ate", "nat", "bat"]输出: [["bat"],["nat","tan"],["ate","eat","tea"]]解释:在 strs 中没有字符串可以通过重新排列来形成 "bat"。字符串 "nat" 和 "tan" 是字母异位词,因为它们可以重新排列以形成彼此。

weixin_68929687的博客 357

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

【算法笔记】力扣热题100(LeetCode hot-100)53. 最大子数组和 1.前缀和 2.动态规划

力扣热题100题 leetcode 53.最大子数组和。给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组,返回其最大和。1:使用前缀和的方法。2:使用动态规划

不想当吗喽的博客 761

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

力扣HOT100热题宝典--第2节

力扣HOT100热题宝典--第2节,二叉树,单调栈

weixin_41171614的博客 897

LeetCode TOP100 热题(2)

如果你时间比较紧迫,为了找工作而刷题,我建议你先刷热门推荐,一共100道题。先刷热题 HOT 100,再刷精选 TOP 面试题,之后刷其他的题。接下来的一段时间,我会把做...

Jerry的编程之路 467

力扣LeetCode 热题 HOT 100 C++ (2/100) 两数相加

力扣LeetCode 热题 HOT 100 C++ (1/100) 两数之和

weixin_51617698的博客 426

LeetCode 热题 100----2.移动零

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

artist123abbb的博客 247

LeetCode热题100-第2题

本题目需要将每个单词分别拆开成单独的字母,其字母组合是唯一的,不存在歧义,因此可以用哈希表将字母组合存储为键,而单词为值进行存储,最后遍历已经存储完毕的哈希表即可。是由重新排列源单词的所有字母得到的一个新单词。可以按任意顺序返回结果列表。给你一个字符串数组,请你将。

qq_56374728的博客 740

leetcode热题100(2)

(2)若a 不等于 b,则指针pA遍历完headA,然后指向headB,指针pB遍历完headB,然后指向headA,然后两个指针继续移动,在指针pA移动了a+c+b次,指针pB移动了b+c+a次之后,两个指针会同时达到相交节点。假设我们知道对于该节点的左儿子向下遍历经过最多的节点数 L (即以左儿子为根的子树的深度) 和其右儿子向下遍历经过最多的节点数 R (即以右儿子为根的子树的深度),那么以该节点为起点的路径经过节点数的最大值即为 L+R+1。是指从根节点到最远叶子节点的最长路径上的节点数。

2401_82749999的博客 1166

LeetCodehot 力扣热题100 跳跃游戏2

i == end,执行 steps++,更新 end = maxReach = 4,终点已到达,跳出循环。i == end,执行 steps++,更新 end = maxReach = 2。我们需要从数组 nums 的起始位置 0 处,跳跃到数组的最后一个位置,并求。其中,nums[i] 表示在索引 i 处最多可以向前跳的步数。,表示当前层的跳跃边界。• 每次跳跃选择在当前范围内能跳得最远的点,保证最少步数。• 只用了几个整型变量,没有额外的数组或数据结构,,表示在当前层范围内,能跳到的最远索引。

qq_51956059的博客 474

力扣刷题-热题100题-第2题(C#、python)

49. 字母异位词分组 - 力扣(LeetCode)c整不动了😭😭😭n字符串数组长度,m是最长字符串的长度。

weixin_44505472的博客 1103

LeetCode 热题 100 之链表2

一些中等链表题目,虚拟dummy~

qq_43060884的博客 943

LeetCode 热题100之回溯2

回溯上强度了~

qq_43060884的博客 794

leetcode热题top100——day2

如果不使用defaultdict方法在访问字典不存在的key值时就要手动赋值。

2302_80723133的博客 230

【练习】【链表】力扣热题100 2. 两数相加

给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]你可以假设除了数字 0 之外,这两个数都不会以 0 开头。输入:l1 = [2,4,3], l2 = [5,6,4]请你将两个数相加,并以相同形式返回一个表示和的链表。输入:l1 = [0], l2 = [0]输出:[8,9,9,9,0,0,0,1]合并,使得代码精简很多。输出:[7,0,8]

2402_86344613的博客 312
上一篇: MySQL---索引特性
下一篇: Linux系统、网络知识点回顾1
bugu___
博客等级 码龄2年 63粉丝 28原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值