Leetcode题库练习笔记(Medium) 美区国区

2023-11-12 00:59

本文主要是介绍Leetcode题库练习笔记(Medium) 美区国区,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Leetcode题库练习笔记(Medium)

    • 两数相加
      • 不完备的题解 解决不了数据溢出
      • 官方题解
    • 8. String to Integer (atoi)
    • 877. Stone Game
      • 不完备的解 贪心算法
      • 经启发后的解 DP
      • 官方数学巧解 不具普适性
    • 547. 省份数量
      • 个人解法:BFS遍历
      • 个人解法2:DFS遍历
    • 5. 最长回文子串
    • 6106. 统计无向图中无法互相到达点对数(连通分支问题)

两数相加

将链表表示的两个非负整数相加,结果也以链表形式返回
https://leetcode-cn.com/problems/add-two-numbers/

不完备的题解 解决不了数据溢出

通过样例1565 / 1568

直接模拟人工计算时的相加过程,提取出两个链表表示的整数,再相加,变回链表,但是A/B链表长度一旦很长,超过unsigend long long表示范围的话就gg了
注意:queue的用法,判空empty(),队头元素是q.front()

/*** 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* addTwoNumbers(ListNode* l1, ListNode* l2) {queue<int> list_1;queue<int> list_2;ListNode* p1=l1;ListNode* p2=l2;while(p1!=nullptr)      //store data in lists{list_1.push(p1->val);p1=p1->next;}while(p2!=nullptr){list_2.push(p2->val);p2=p2->next;}unsigned long long num1=0,num2=0,i=0;      //calculate value of listswhile(list_1.empty()!=1){num1+=list_1.front()*pow(10,i);list_1.pop();i++;}i=0;while(list_2.empty()!=1){num2+=list_2.front()*pow(10,i);list_2.pop();i++;}unsigned  long long sum=num1+num2;queue<int>res;while(sum!=0){int n=sum%10;res.push(n);    //lower digit pushed first, to be poped firstsum=sum/10;}ListNode* p=new ListNode;ListNode* newlist=p;//save the list headwhile(res.empty()!=1){p->val=res.front();res.pop();if(res.empty()==1){break;}ListNode* q=new ListNode;q->val=0;q->next=nullptr;//initialize the next nodep->next=q;p=p->next;}return newlist;}
};

官方题解

不用转换格式(链表——>整数——>链表),直接边加变构造新的链表,每个节点填入的值是res=A+B+进位的个位,下一个结点的进位是res的十位
公式如下: r e s = [ A + B + C a r r y 10 ] res= [\frac{A+B+Carry}{10}] res=[10A+B+Carry] C a r r y i = ( A + B + C a r r y i − 1 ) % 10 Carry_{i}= (A+B+Carry_{i-1}) \%10 Carryi=(A+B+Carryi1)%10

只要逐位边加边构造链表,就不存在数字过大溢出的问题了

/*** 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* addTwoNumbers(ListNode* l1, ListNode* l2) {ListNode *head = nullptr, *tail = nullptr;int carry = 0;while (l1 || l2) {int n1 = l1 ? l1->val: 0;int n2 = l2 ? l2->val: 0;int sum = n1 + n2 + carry;if (!head) {head = tail = new ListNode(sum % 10);} else {tail->next = new ListNode(sum % 10);tail = tail->next;}carry = sum / 10;if (l1) {l1 = l1->next;}if (l2) {l2 = l2->next;}}if (carry > 0) {tail->next = new ListNode(carry);}return head;}
};

8. String to Integer (atoi)

Implement the myAtoi(string s) function, which converts a string to a 32-bit signed integer (similar to C/C++'s atoi function).
题目要求:实现字符串string类型转换成int类型的函数
原题目地址
暴力枚举法即可

int myAtoi(string s)
{int sign = 1;bool signflag = 0;bool zeroflag = 0;//0表示有可能出现“前面的0”; 1则相反vector<int> st;for (int i = 0; i < s.size(); i++){if (signflag == 0 && s[i] == ' ')continue;else if (signflag == 0 && s[i] == '+')signflag = 1;else if (signflag == 0 && s[i] == '-')signflag = 1, sign = -1;else if (s[i] == '0')//检查是否为“前面的0 ” {if (zeroflag == 1){signflag = 1, st.push_back(0);}else signflag = 1;//跳过 }else if (s[i] > '0' && s[i] <= '9')signflag = zeroflag = 1, st.push_back(s[i] - 48);//注意ASCII转换elsebreak;//其他情况(出现字母etc),直接跳出循环,输出已扫描到的合法部分}int n = 0;long long num = 0, sum = 0;//循环计次 while (!st.empty()){num = st.back();st.pop_back();num *= pow(10, n);sum += num;n++;if (n > 10)//防止数字过大,中途num溢出{if (sign == 1)return  pow(2, 31) - 1;else return-pow(2, 31);}}long long res = sign * sum;if (res > pow(2, 31) - 1)res = pow(2, 31) - 1;else if (res < -pow(2, 31))res = -pow(2, 31);return res;
}

877. Stone Game

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

不完备的解 贪心算法

起初考虑了贪心算法+模拟
但是贪心算法(每一次都最两边之一较大的值)不能保证得到最优解,只有部分问题(Kruskal/prim最小生成树等算法中等同于最优解)

bool stoneGame1(vector<int>& piles) {int n = piles.size();int sumA = 0, sumB = 0, i, j = n - 1, k = 0;vector<bool>flags(n);//record if a pile has been taken(1)for (i = 1; i <= n && j >= k; i++)//simiulate every turn{if (i % 2 == 1)//aliceif (piles[k] > piles[j]){sumA += piles[k]; k++;}else{sumA += piles[j]; j--;}elseif (piles[k] > piles[j]){sumB += piles[k]; k++;}else{sumB += piles[j]; j--;}int restSum = accumulate(piles.begin() + k, piles.begin() + j + 1, 0);if (sumA > sumB + restSum) return true;}return false;
}

经启发后的解 DP

构造动态规划就需要先构造递推方程,也就是先构造DP表项

  • 首先,DP表项的角标必须等价于当前状态
  • 其次,DP表项的取值必须能直接转换成解并输出
    进而,状态转移表项DP[i,j]就可以表示状态[i,j]下的最优解,成功构造DP后只需要迭代到目标DP表项,比如DP[0][n-1]然后输出即可
    目前就见过的算法题而言,DP表项的角标最多两个(i,j即可一一对应一个状态),但在算法课上曾见到一道连续矩阵相乘最值的问题,涉及到三个角标
//动态规划 构造dp[i][j] 为面对piles[i~j]时当前玩家能拿到的分数最大值(max{石头总和})
//由此看出构造DP表项的两大要素:
//1、精准指明当前状态(往往1~2个角标) 2、表项取值本身==当前最优解(像这样要输出bool的解则要准确取值,直接判T/F)
bool stoneGame(vector<int>& piles) {const int N = 501;int dp[N][N] = { 0 };int sum = accumulate(piles.begin(), piles.end(), 0);int n = piles.size();int i = 0, j = n - 1,k=1;for (k = 1; j >= i; k++){int last1=0, last2=0;if (i > 0)last1 = dp[i - 1][j];if (j < n - 1)last2 = dp[i][j + 1];if (last1 + piles[i] > last2 + piles[j]){dp[i][j] = last1 + piles[i];if (k % 2 == 1 && dp[i][j] > sum / 2)return true;i++;}else{dp[i][j] = last2 + piles[j];if (k % 2 == 1 && dp[i][j] > sum / 2)return true;j--;}}return false;
}

官方数学巧解 不具普适性

组合数学可以构造证明:先下手的A永远有必胜策略,可以将piles[i] (i=0, 2, 4, …)涂成黑色,将piles[i] (i=1, 3, 5, …)涂成红色,先出手的一方总可以保证只取一种颜色的堆直到结束,而两种颜色石头数量之和必然有一方大于另一方(因为总数是奇数,不存在平局),所以借由2元上色的方式构造证明了先手必赢。

    bool stoneGame(vector<int>& piles) {return true}

547. 省份数量

题目:leetcode国区——省份数量
在这里插入图片描述

个人解法:BFS遍历

牢记BFS特征:用栈存储一个节点所有的邻接点(包括自己),先入栈后出栈,出栈时标记该点已经被访问

void bfs(vector<vector<int>>& isConnected, int start, vector<int>& flags)
{int i, j;int n = isConnected.size();vector<int>Neighbors;Neighbors.push_back(start);while (Neighbors.size() > 0){int newN = Neighbors.back();Neighbors.pop_back();flags[newN] = 1;for (j = 0; j < n; j++)if (isConnected[newN][j] && flags[j] == 0){Neighbors.push_back(j);}}
}int findCircleNum(vector<vector<int>>& isConnected) {int i, res = 0,j;int n = isConnected.size();vector<int> flags(n);for (i = 0; i < n; i++){if (flags[i] == 1)continue;bfs(isConnected,i,flags);res++;}return res;
}

个人解法2:DFS遍历

牢记DFS特征:递归,dfs()里调用dfs()
使用Python可以用语法糖扩大栈空间

void dfs(vector<vector<int>>& isConnected, int start, vector<int>&flags)
{int i;bool not_counted = 1;int n = isConnected.size();flags[start] = 1;for (i = 0; i < n; i++){if (isConnected[i][start] && flags[i] == 0){dfs(isConnected, i, flags);}}
}int findCircleNum(vector<vector<int>>& isConnected) {int i, res = 0, j;int n = isConnected.size();vector<int> flags(n);for (i = 0; i < n; i++){if (flags[i] == 1)continue;dfs(isConnected, i, flags);res++;}return res;}

简化此题:很多时候DFS写不出来总是因为dfs()的参数太多,容易想错:
实际只需要传入一个参数:被dfs()的端点本身,一般是int表示,如这里的int start

  • 如果问题数据规模小:其他参数一律写成全局变量,一开始申请足够空间
  • 如果问题数据规模大:dfs()用函数模声明和定义成主要函数(这里的findCircleNum)的嵌套定义的函数
function<type(args_type)>funcName=[](args)
{/*function body*/};    //别忘了分号

function<T>定义的函数可以定义在其他函数里面或者外面,很适合定义dfs()!

5. 最长回文子串

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

  • 构造最优子结构
    在这里插入图片描述
    进一步细化
    在这里插入图片描述
    边界条件是长度为1或2的字串:
    在这里插入图片描述
  • 迭代填表的时候需要确保子问题的解已经计算出来(注意迭代顺序)
    外层约束是j,内层是i,确保子问题的解 d p [ i + 1 ] [ j − 1 ] dp[i+1][j-1] dp[i+1][j1]在调用的时候已被计算完毕
    在这里插入图片描述

6106. 统计无向图中无法互相到达点对数(连通分支问题)

题目:
在这里插入图片描述
本质上是找图的连通分支(由多少个连通的子图组成)

用DFS找出所有连通分支,统计每个连通分支的点数,所求两两组合数目res=res+新发现的连通分支点数 × \times ×之前所有(分支的)点数之和
牢记dfs()函数的写法:

  • 如果问题数据规模小:其他参数一律写成全局变量,一开始申请足够空间
  • 如果问题数据规模大:dfs()用函数模声明和定义成主要函数(这里的findCircleNum)的嵌套定义的函数
    dfs()的参数一般只需一个x就够
long long countPairs(int n, vector<vector<int>>& edges) {//转换数据结构vector<vector<int>>g(n);for (auto& e : edges){int x = e[0], y = e[1];g[x].push_back(y);g[y].push_back(x);}vector<bool>visit(n);//int block = 0;   //统计连通分支的个数,但是用不上long long  prev = 0; //之前遇到的分支的点总和int count = 0;//每个分支内有多少点function<void(int)>dfs = [&](int x) //!函数内嵌套函数 (这样可以少开visit空间){if (visit[x] == 0){visit[x] = 1;count++;for (int p : g[x])//对于x的每一个邻接点执行dfsdfs(p);//block++;}};long long res = 0;for (int i = 0; i < n; i++){if (!visit[i]){count = 0;dfs(i);//进入dfs,算出这个分支区的countres += count * prev;//res+=新的分支点数*之前记录的所有点数prev += count;}}return res;
}

这篇关于Leetcode题库练习笔记(Medium) 美区国区的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/394013

相关文章

哈希leetcode-1

目录 1前言 2.例题  2.1两数之和 2.2判断是否互为字符重排 2.3存在重复元素1 2.4存在重复元素2 2.5字母异位词分组 1前言 哈希表主要是适合于快速查找某个元素(O(1)) 当我们要频繁的查找某个元素,第一哈希表O(1),第二,二分O(log n) 一般可以分为语言自带的容器哈希和用数组模拟的简易哈希。 最简单的比如数组模拟字符存储,只要开26个c

2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题

题库来源:安全生产模拟考试一点通公众号小程序 2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题是由安全生产模拟考试一点通提供,流动式起重机司机证模拟考试题库是根据流动式起重机司机最新版教材,流动式起重机司机大纲整理而成(含2024年流动式起重机司机证模拟考试题库及流动式起重机司机理论考试试题参考答案和部分工种参考解析),掌握本资料和学校方法,考试容易。流动式起重机司机考试技

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

RabbitMQ练习(AMQP 0-9-1 Overview)

1、What is AMQP 0-9-1 AMQP 0-9-1(高级消息队列协议)是一种网络协议,它允许遵从该协议的客户端(Publisher或者Consumer)应用程序与遵从该协议的消息中间件代理(Broker,如RabbitMQ)进行通信。 AMQP 0-9-1模型的核心概念包括消息发布者(producers/publisher)、消息(messages)、交换机(exchanges)、

leetcode-24Swap Nodes in Pairs

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode swapPairs(L

leetcode-23Merge k Sorted Lists

带头结点。 /*** Definition for singly-linked list.* public class ListNode {* int val;* ListNode next;* ListNode(int x) { val = x; }* }*/public class Solution {public ListNode mergeKLists

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

论文阅读笔记: Segment Anything

文章目录 Segment Anything摘要引言任务模型数据引擎数据集负责任的人工智能 Segment Anything Model图像编码器提示编码器mask解码器解决歧义损失和训练 Segment Anything 论文地址: https://arxiv.org/abs/2304.02643 代码地址:https://github.com/facebookresear

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟)

【每日一题】LeetCode 2181.合并零之间的节点(链表、模拟) 题目描述 给定一个链表,链表中的每个节点代表一个整数。链表中的整数由 0 分隔开,表示不同的区间。链表的开始和结束节点的值都为 0。任务是将每两个相邻的 0 之间的所有节点合并成一个节点,新节点的值为原区间内所有节点值的和。合并后,需要移除所有的 0,并返回修改后的链表头节点。 思路分析 初始化:创建一个虚拟头节点