Leetcode Easy题小解(C++语言描述)1

Leetcode Easy题小解(C++语言描述)

相交链表

给你两个单链表的头节点 headAheadB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null

图示两个链表在节点 c1 开始相交**:**

在这里插入图片描述

题目数据 保证 整个链式结构中不存在环。

注意,函数返回结果后,链表必须 保持其原始结构

方法一:使用unordered_set存储元素查询是否重复

​ 有一个招数就是使用unordered_set存储一下我们的一个链表的元素,然后,去用另一个链表遍历查看我们的元素是否在unordered_set种已经出现过了。

class Solution {
public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {unordered_set<ListNode*> sets;// init the sets to get the count;while(headA){sets.insert(headA);headA = headA->next; // go ahead;}while(headB){if(sets.count(headB)){// owns the count, and returns;return headB;}headB = headB->next;}return nullptr;}
};

​ 这种方式最直观,也是笔者的第一反应。

方法2:快慢指针判决

​ 下面我们来看快慢指针的办法进行求解。我们知道,假设A链表的长度是a,B链表的长度是b,公共部分设成c,那么显然,我们快慢指针的判别法可以是这样的:即尝试两个指针都走一次A,B链表,当走到我们的焦点的时候,我们发现:

A: 走了 a + (b - c)
B: 走了 b + (a - c)

​ 我们高兴的发现两个指针走的部署相等,因此实际上,我们完全就让快慢指针在交点处相等了。

class Solution {
public:ListNode *getIntersectionNode(ListNode *headA, ListNode *headB) {ListNode* curA = headA;ListNode* curB = headB;while(curA != curB){curA = (curA ? curA->next : headB); // 空了咱们去BcurB = (curB ? curB->next : headA); // 空了咱们去A}return curA;}
};

链表反转

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

/*** Definition for singly-linked list.* struct ListNode {*     int val;*     ListNode *next;*     ListNode() : val(0), next(nullptr) {}*     ListNode(int x) : val(x), next(nullptr) {}*     ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/

​ 反转链表比较简单,我们实际上的难点在于,我们不能立马修改当前遍历节点的下一个节点,需要做缓存

class Solution {
public:ListNode* reverseList(ListNode* head) {if(!head || !head->next) return head; // stop with null and onlyListNode* current = head;ListNode* prev = nullptr;ListNode* next_one;while(current){// cached the next onenext_one = current->next;// modify the next one's next to the cur to reversecurrent->next = prev;// restore cachesprev = current;current= next_one;}return prev;}
};

​ 就可以看到,我们做的实际上就是简单的swap操作,没啥好说的。

判断回文链表

​ 给你一个单链表的头节点 head ,请你判断该链表是否为回文链表。如果是,返回 true ;否则,返回 false 。

​ 嘛!显然,咱们没法逆序遍历链表,有一种偷懒的办法兄弟们,那就是用一下栈这个特性。我们知道栈是一个经典的FILO结构,我们按照遍历顺序压栈我们的单链表遍历结果,之后我们只需要再遍历一下链表,跟我们的栈进行对比

class Solution {
public:bool isPalindrome(ListNode* head) {stack<int> caches;ListNode* cached_head = head;while(head){caches.push(head->val);head = head->next;}     while(cached_head){if(cached_head->val != caches.top()){return false;}cached_head = cached_head->next;caches.pop();}return true;}
};

前K系列:找出前K个高频元素

​ 给你一个整数数组 nums 和一个整数 k ,请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。

​ 其实回答很简单,那就是第一步是统计我们的元素个数,我们可以使用的是unordered_map来做这个事情,其键值对我们采用的是:{元素,个数}键值对。之后咱们做的事情就是塞到大根堆进行默认的排序。需要注意的是,咱们的大根堆对pair的排序看的是第一个数大不大,所以咱们往队列里push我们的东西的时候,是需要我们调换一下键值对的顺序的。

class Solution {
public:vector<int> topKFrequent(vector<int>& nums, int k) {unordered_map<int, int> counters; // <nums, count>for(const auto& num : nums){counters[num]++;}// next, we shell check and reordered as prioirty queuepriority_queue<pair<int, int>> pq;for(const auto& each : counters){pq.push({each.second, each.first});}vector<int> result;for(int i = 0; i < k; i++){result.emplace_back(pq.top().second);pq.pop();}return result;}
};

​ 可以看到我们的priority_queue自动帮助我们处理排序的事情了。如果是小K个,那么我们只需要换greater<int>就好了

第K系列:使用O(N)复杂度寻找第K个大小的数字

可以用sort等嘛?

​ 不能,因为std::sort是完全快排,实际上复杂度是O(NlogN),我们需要改进成快速选择的方式进行改进

class Solution {
public:int partition(vector<int>& nums, int left, int right){int pivot = nums[right];int i = left;for(int j = left; j < right; j++){if(nums[j] <= pivot){swap(nums[i], nums[j]);i++;}}swap(nums[i], nums[right]);return i; // return new pivot}int quick_selection(vector<int>& n, int left, int right, int k_smallest){if (left == right) return n[left];int pivot = partition(n, left, right);if(pivot == k_smallest){return n[pivot];}else if (pivot < k_smallest){// leftreturn quick_selection(n, pivot + 1, right, k_smallest);}else{return quick_selection(n, left, pivot - 1, k_smallest);}}int findKthLargest(vector<int>& nums, int k) {int n = nums.size();int target = n - k; // 第 k 大 → 第 n - k 小return quick_selection(nums, 0, n - 1, target);}
};

1. findKthLargest 函数:“化大为小,找对目标”

想象你有一堆扑克牌,现在让你找出第 3 大的那张牌。

int findKthLargest(vector<int>& nums, int k) {int n = nums.size();// 关键一步:把“找第k大”转换成“找第(n-k)小”int target = n - k; // 例如,有5张牌,找第1大(最大的),就是找第5-1=4小的(也就是索引为4的,如果从0开始数)// 找第3大,就是找第5-3=2小的(也就是索引为2的)return quick_selection(nums, 0, n - 1, target);
}
  • 它的任务: 你告诉我,你想要这堆牌里第几大的牌。
  • 它的聪明之处: 它会偷偷地把你的要求“翻译”一下。比如,如果你说要找第 3 大的牌,它会心想:“哦,这不就是说,在所有牌都排好序之后,从最小的开始数,第 (N−3) 张牌吗?”(N 是总牌数)。
  • 委托任务: 翻译完之后,它就把这个“找第 N−k 小的牌”的任务,交给下一级的专家 quick_selection 去办了。

2. partition 函数:“分堆、找个好位置”

这个函数是整个算法的“幕后功臣”,它每次的作用是:随机挑一个“参考牌”,然后把其他牌根据这个参考牌分成两堆。

int partition(vector<int>& nums, int left, int right)
{int pivot = nums[right]; // 选定最右边的牌作为“参考牌”(基准值)int i = left;            // i 指针:表示“比参考牌小的牌”的区域的右边界// j 指针从左边开始遍历,但不到right(因为right是参考牌)for(int j = left; j < right; j++){if(nums[j] <= pivot){ // 如果当前牌(nums[j])比“参考牌”小或者相等swap(nums[i], nums[j]); // 就把这张牌挪到“比参考牌小的区域”里去i++;                     // “比参考牌小的区域”的边界就往右扩大一格}}// 循环结束后,i 指向的位置,就是所有“比参考牌小的牌”后面紧跟着的位置// 也就是说,i左边的牌都 <= pivot,i右边的牌都 > pivot (暂时)swap(nums[i], nums[right]); // 把“参考牌”(nums[right])放到 i 指向的位置// 这样,i位置的牌就是新的参考牌,它左边的都比它小,右边的都比它大return i; // 返回这个“参考牌”最终所在的位置(索引)
}
  • 它的任务: 拿到一堆牌(一个子数组),然后重新整理一下这堆牌。

  • 怎么整理:

    1. 它先从这堆牌的最右边挑一张牌,把它作为**“参考牌” (pivot)**。
    2. 它有一个**“小牌区”的边界 i**,最开始在最左边。
    3. 然后它从最左边开始,一张一张地看牌 (j 遍历):
      • 如果它看的这张牌比“参考牌”小(或者一样大),那么这张牌就应该放在“小牌区”里。它就会把这张牌和“小牌区”边界 i 上的牌交换一下位置。然后,“小牌区”的边界 i 就往右移一位。
      • 如果它看的这张牌比“参考牌”大,它就不管,继续看下一张。
    4. 当所有牌都看完了(j 走到了 right - 1),这时候,从起始位置到 i-1 的所有牌都比“参考牌”小或相等。i 指向的牌和 i 右边的牌都比“参考牌”大(或者还没有处理的牌)。
    5. 最后,它会把最开始选定的那张**“参考牌”**(原来在 right 位置)放到 i 所指的位置上。
  • 结果: partition 函数执行完后,数组就变成这样:

    [小于等于参考牌的牌 | 参考牌本身 | 大于参考牌的牌]

    而且,返回的 i 就是这个**“参考牌”最终所在的位置**。这个位置非常重要,因为它告诉我们“参考牌”在整个排序好之后,会处于哪个确切的索引。


3. quick_selection 函数:“缩小范围,直到找到”

这是递归寻找目标牌的主管。

int quick_selection(vector<int>& n, int left, int right, int k_smallest){if (left == right) return n[left]; // 如果只剩一张牌了,那这张牌就是答案,直接返回int pivot_index = partition(n, left, right); // 调用 partition,找到“参考牌”的新位置if(pivot_index == k_smallest){// 情况1:运气真好!“参考牌”的位置正好就是我们要找的第k_smallest小牌的位置!return n[pivot_index]; // 找到了,直接返回这张牌}else if (pivot_index < k_smallest){// 情况2:“参考牌”的位置比我们想找的牌的位置靠左了// 说明我们想找的牌在“参考牌”的右边那堆牌里return quick_selection(n, pivot_index + 1, right, k_smallest); // 递归去右边那堆牌里找}else{// 情况3:“参考牌”的位置比我们想找的牌的位置靠右了// 说明我们想找的牌在“参考牌”的左边那堆牌里return quick_selection(n, left, pivot_index - 1, k_smallest); // 递归去左边那堆牌里找}
}
  • 它的任务: 在指定的牌堆范围 (leftright) 里,找到“翻译”后的那个 k_smallest 索引的牌。
  • 怎么找:
    1. 基地情况: 如果这堆牌里只剩下一张牌了(left == right),那这张牌肯定就是我们要找的,直接拿走。
    2. 分区: 否则,它会调用 partition 函数,把当前这堆牌重新分一下,得到一个**“参考牌”的新位置 pivot_index**。
    3. 判断:
      • 正好找到! 如果这个 pivot_index 恰好就是我们要找的 k_smallest 索引,那太好了!pivot_index 上的那张牌就是答案,直接返回!
      • 找错了,往右边找! 如果 pivot_indexk_smallest 小,说明“参考牌”排得太靠左了,我们要找的牌肯定在它的右边那堆牌里。所以,它会pivot_index + 1right 的范围里,继续用同样的方法找 k_smallest 索引的牌。
      • 找错了,往左边找! 如果 pivot_indexk_smallest 大,说明“参考牌”排得太靠右了,我们要找的牌肯定在它的左边那堆牌里。所以,它会leftpivot_index - 1 的范围里,继续用同样的方法找 k_smallest 索引的牌。

这个算法的核心思想就是:

  1. 我有一堆乱序的牌。
  2. 我想找到第 N−k 小的那张牌。
  3. 我随机(这里是选最右边)挑一张牌作为“参考牌”。
  4. 我把所有比“参考牌”小的牌挪到它左边,所有比它大的牌挪到它右边。然后把“参考牌”放到它最终该去的位置。
  5. 现在“参考牌”的位置确定了。
  6. 我就看这个“参考牌”的位置是不是我想要的那个第 N−k 小的索引。
    • 如果是,那我就找到了!
    • 如果不是,我就只去“参考牌”的左边那堆牌或者右边那堆牌里继续找(因为我知道我要的牌肯定在那一堆里),另一堆牌就完全不用管了。
  7. 这样,每次都能排除掉一部分不需要查找的牌,大大提高了效率。

它和快速排序最大的不同是,快速排序要排序两边,而快速选择只排序包含目标元素的那一边,所以平均情况下比完全排序要快得多。

**

  1. 我有一堆乱序的牌。
  2. 我想找到第 N−k 小的那张牌。
  3. 我随机(这里是选最右边)挑一张牌作为“参考牌”。
  4. 我把所有比“参考牌”小的牌挪到它左边,所有比它大的牌挪到它右边。然后把“参考牌”放到它最终该去的位置。
  5. 现在“参考牌”的位置确定了。
  6. 我就看这个“参考牌”的位置是不是我想要的那个第 N−k 小的索引。
    • 如果是,那我就找到了!
    • 如果不是,我就只去“参考牌”的左边那堆牌或者右边那堆牌里继续找(因为我知道我要的牌肯定在那一堆里),另一堆牌就完全不用管了。
  7. 这样,每次都能排除掉一部分不需要查找的牌,大大提高了效率。

它和快速排序最大的不同是,快速排序要排序两边,而快速选择只排序包含目标元素的那一边,所以平均情况下比完全排序要快得多。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/89133.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/89133.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EP01:【NLP 第二弹】自然语言处理概述

一、NLP通向智能之路 1.1 图灵测试 1.1.1 提出背景 由计算机科学家阿兰・图灵于 1950 年提出&#xff0c;是早期衡量机器智能水平的重要概念。 1.1.2 提出目的 判断机器是否能表现出与人类相当的智能行为。 1.1.3 测试原理 场景设定&#xff1a;测试中存在一位人类测试者&#…

Ansible 查看PostgreSQL的版本

Ansible的基础知识就不说了直接贴剧本- name: Check PostgreSQL versionhosts: db_serversbecome: yesvars:ansible_python_interpreter: /usr/bin/python3db_name: postgresdb_user: postgresdb_password: your_passwordtasks:- name: Install psycopg2ansible.builtin.packag…

【视觉SLAM笔记】第9章 后端1

一、理论1. 状态估计的概率解释我们来深入探讨一下视觉SLAM中状态估计的概率解释。这可以说是理解现代SLAM算法&#xff08;尤其是后端优化&#xff09;的基石1. 问题的核心&#xff1a;不确定性SLAM&#xff08;同步定位与建图&#xff09;的本质是在一个未知环境中&#xff0…

(数据结构)复杂度

基本概念说明 数据结构 定义&#xff1a;数据结构(Data Structure)是计算机存储、组织数据的方式&#xff0c;指相互之间存在⼀种或多种特定关系的数据元素的集合。没有⼀种单⼀的数据结构对所有用途都有用&#xff08;要考虑适配、效率问题&#xff0c;在不同情况下使用合适的…

玩转Docker | 使用Docker部署bender个人导航页工具

玩转Docker | 使用Docker部署bender个人导航页工具 前言 一、bender介绍 Bender 简介 Bender 的主要特点 二、系统要求 环境要求 环境检查 Docker版本检查 检查操作系统版本 三、部署bender服务 下载bender镜像 编辑部署文件 创建容器 检查容器状态 检查服务端口 安全设置 四、…

解决了困扰我的upload靶场无法解析phtml等后缀的问题

本文章为解决困扰我的 upload 靶场无法解析 phtml 问题 ​ 这个问题直接让我过不了Upload-Pass-03这一关&#xff0c;一直卡着。 ​ 痛太痛了 &#xff0c;为什么无法解析上传之后的 phtml 后缀文件&#xff01;这块儿折磨了博主一天多&#xff0c;太不容易了&#xff0c;查找…

Leetcode百题斩-二分搜索

二分搜索也是一个很有趣的专题&#xff0c;被做过的题中&#xff0c;刚好一个Easy&#xff0c;一个Medium和一个Hard&#xff0c;刚好可以看看&#xff0c;二分搜索的三个难度等级都是啥样的。 124. Binary Tree Maximum Path Sum[Hard]&#xff08;详见二叉树专题&#xff09;…

【IDEA】格式化代码工具配置

格式化代码快捷键&#xff1a; CtrlAltL格式代码的时候不会再方法名与参数中间添加空格默认不勾选的情况下&#xff1a;代码样例&#xff1a;勾选之后的样例&#xff1a;选择不勾选&#xff0c;IDEA默认情况下就是不勾选的状态忽略加载文件有些非必要加载到开发工具中的文件我们…

驱动开发(3)|rk356x驱动GPIO基础应用之点亮led灯

点亮LED灯看似是一个基础的操作&#xff0c;但实际上&#xff0c;许多高级应用也依赖于高低电平的切换。例如&#xff0c;脉冲宽度调制&#xff08;PWM&#xff09;信号可以用来精确控制电机的转速&#xff0c;通过改变脉冲的频率和占空比&#xff0c;实现对电机的精确调节&…

手动搭建PHP环境:步步为营,解锁Web开发

目录一、引言二、准备工作2.1 明确所需软件2.2 下载软件三、Windows 系统搭建步骤3.1 安装 Apache 服务器3.2 安装 PHP3.3 集成 Apache 与 PHP3.4 安装 MySQL3.5 配置 PHP 连接 MySQL四、Linux 系统搭建步骤&#xff08;以 Ubuntu 为例&#xff09;4.1 更新系统4.2 安装 Apache…

DrissionPage:一款让网页自动化更简单的 Python 库

在网页自动化领域&#xff0c;Selenium 和 Playwright 早已是开发者耳熟能详的工具。但今天要给大家介绍一款更轻量、更易用的 Python 库 ——DrissionPage。它以 "融合 selenium 和 requests 优势" 为核心设计理念&#xff0c;既能像 requests 一样高效处理静态网页…

理解Grafana中`X-Scope-OrgID`的作用与配置

X-Scope-OrgID的作用 该HTTP Header用于标识Loki日志数据的所属租户&#xff08;组织&#xff09;。在多租户模式下&#xff0c;Loki通过此Header隔离不同团队或用户的数据&#xff0c;确保查询和存储的独立性。数据隔离&#xff1a; 租户A的日志标记为X-Scope-OrgID: team-a&a…

【PycharmPyqt designer桌面程序设计】

在 main.py 中调用 Qt Designer 生成的 windows.py&#xff08;假设它是 PySide2 版&#xff09;。 只要把两个文件放在同一目录即可直接运行。 ──────────────────── 1️⃣ windows.py&#xff08;Qt Designer 生成&#xff0c;已转码&#xff09; # -*-…

Unity Android Logcat插件 输出日志中文乱码解决

背景之前安卓真机调试看日志&#xff0c;一直用的是Android Studio自带的adb命令进行看日志&#xff0c;不太方便&#xff0c;改用Unity自带的安卓日志插件时&#xff0c;存在中文日志乱码问题。插件安装基于Unity6000.1.11版本&#xff1a;Window -> Package Management -&…

Halcon双相机单标定板标定实现拼图

1.Halcon图像拼接算法在之前的文章里也写过&#xff0c;主要是硬拼接和特征点拼接两种方式&#xff0c;今天增加另一种拼接图像的方式。应用场景是多个相机联合一起拍大尺寸的物体&#xff0c;并且相机视野之间存在重叠区域。通过在同一个标定板上面标定&#xff0c;计算两个相…

动物世界一语乾坤韵芳华 人工智能应用大学毕业论文 -仙界AI——仙盟创梦IDE

提示词在一个奇幻的童话森林里&#xff0c;所有的动物都像人类一样直立行走&#xff0c;穿着各种搞怪的衣服。 一只戴着超大眼镜、穿着背带裤的乌龟&#xff0c;正一本正经地站在一个蘑菇舞台上&#xff0c;拿着一根树枝当作麦克风&#xff0c;准备唱歌。它的眼镜总是往下滑&am…

SpringBoot(原理篇)

大家好&#xff0c;这里是 盛码笔记。 本篇我们来聊一聊 Spring Boot 的“魔法”是如何实现的。你可能已经用过 Spring Boot 快速搭建项目&#xff0c;但有没有想过&#xff1a;为什么只需要引入几个 starter&#xff0c;Spring Boot 就能自动配置好整个应用环境&#xff1f; …

数据结构:栈(区间问题)

码蹄集OJ-小码哥的栈 #include<bits/stdc.h> using namespace std; #define int long long const int N1e67; struct MOOE {int ll,rr; }; stack<MOOE>st; signed main( ) {ios::sync_with_stdio(false);cin.tie(nullptr);int n;cin>>n;while(n--){int opt…

Vue 中 data、watch、created 和 methods

以下是 Vue 中 data、watch、created 和 methods 的详细解释&#xff0c;结合常见使用场景和示例&#xff1a;1. data&#xff1a;响应式数据容器 作用&#xff1a;定义组件的响应式数据&#xff08;状态&#xff09;&#xff0c;当数据变化时&#xff0c;视图自动更新。特点&a…

精密模具冷却孔内轮廓检测方法探究 —— 激光频率梳 3D 轮廓检测

引言精密模具冷却孔的内轮廓精度直接影响注塑成型效率与制品质量。冷却孔具有深径比大&#xff08;可达 25:1&#xff09;、结构复杂&#xff08;多为螺旋形或异形&#xff09;、表面质量要求高&#xff08;Ra≤0.2μm&#xff09;等特点&#xff0c;传统检测方法难以满足其高精…