目录
9、删除链表的倒数第N个节点 - 链表 + 快慢指针 / 栈

思路:
建立map,mp[nums[i]]=i 存储值所对应的下标
顺序遍历每一个元素,先查找mp中是否存在与nums[i]匹配的值(target-nums[i])
如果存在,则返回【i,匹配值下标i】
否则将该nums[i]存入map中
为什么先查找,再存哈希表?
因为题目要求,数组中同一元素不能重复出现,所以当遍历到自己时,先查找之前有没有存在的匹配值,再进行存储,这样避免了匹配到自己的情况
- class Solution {
- public int[] twoSum(int[] nums, int target) {
- Map
mp = new HashMap<>(); - for(int i=0; i < nums.length; i++ )
- {
- int t = target - nums[i];
- if(mp.containsKey(t)) return new int[] {mp.get(t),i};
- mp.put(nums[i],i);
- }
- return new int[] {};
- }
- }
- class Solution {
- public:
- vector<int> twoSum(vector<int>& nums, int target) {
- int n=nums.size();
- map<int,int> mp;
- for(int i=0;i
- {
- int t=target-nums[i];
- if(mp.find(t)!=mp.end())
- return {i,mp.find(t)->second};
- mp[nums[i]]=i;
- }
- return{};
- }
- };
2、两数相加 - 链表

思路:
l1和l2指针顺序向后遍历两链表
如果指到非空节点,存下各位之和sum和进位数t
注意:如果遍历到最后仍有进位,需要再在链表后新增节点
-
- class Solution {
- public:
- ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
- ListNode *head = nullptr,*tail = nullptr;
- int t = 0;
- while(l1||l2)
- {
- int x1 = l1? l1->val:0;
- int x2 = l2? l2->val:0;
- int sum = (x1+x2+t)%10;
- t = (x1+x2+t)/10;
- if(!head)
- head = tail = new ListNode(sum);
- else{
- tail->next = new ListNode(sum);
- tail = tail->next;
- }
- if(l1) l1 = l1->next;
- if(l2) l2 = l2->next;
- }
- if(t>0) tail->next = new ListNode(t);
- return head;
- }
- };
-
- class Solution {
- public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
- ListNode dummy=new ListNode();
- ListNode cur=dummy;
- int t=0;
- while(l1!=null||l2!=null||t>0)
- {
- if(l1!=null) t+=l1.val;
- if(l2!=null) t+=l2.val;
- cur=cur.next=new ListNode(t%10);
- t=t/10;
- if(l1!=null) l1=l1.next;
- if(l2!=null) l2=l2.next;
- }
- return dummy.next;
- }
- }
3、无重复字符的最长子串 - 滑动窗口

思路:
用set判重,双指针实现滑动窗口
用maxx更新最长长度
如果窗口内出现重复元素,缩左边界,并将不在窗口内的字符删去,直至窗口内无重复元素
即若窗口内无重复元素,向右增大窗口,并更新最大长度,直至出现重复元素,缩小窗口,最后滑窗遍历完整个字符串,取最大窗口长度
- class Solution {
- public:
- int lengthOfLongestSubstring(string s) {
- set<char> word;
- int st=0,maxx=0;
- for(int ed=0;ed
- {
- while(word.count(s[ed]))
- {
- word.erase(s[st]);
- st++;
-
- if(!word.count(s[ed]))continue;
- }
- if(ed-st+1>maxx) maxx=ed-st+1;
- word.insert(s[ed]);
- cout<
' '< - }
- return maxx;
- }
- };
4、寻找两个正序数组的中位数 - 暴力合并两数组

思路:
暴力求解,没啥好说的,进阶的不想看
- class Solution {
- public:
- double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
- int m=nums1.size(),n=nums2.size();
- cout<
" "< - int t=m+n+10;
- int arr[t];
-
- int l1=0,l2=0,cnt=0;
- while(l1
- {
- if(nums1[l1]>nums2[l2]) arr[cnt++]=nums2[l2],l2++;
- else arr[cnt++]=nums1[l1],l1++;
- }
- while(l1
- while(l2
- if((m+n)%2) return arr[(m+n-1)/2];
- else return (arr[(m+n)/2]+arr[(m+n)/2-1])*1.0/2;
- }
- };
5、最长回文子串 - 中心扩展法 + dp动态规划

常规暴力O(n^3) 会tle
(1)中心扩展法
思路:
枚举每一个字符s[i],同时设置左右指针l=i-1,r=i+1,最长回文子串长度len
如果该子串为回文串,会有如下三种情况:
- 左指针和中心字符相等,len+1,例如:abaacb
- 右指针和中心字符相等,len+1,例如:abcaab
- 左指针和右指针字符相等,len+2,如:abcacb
如果左右指针不越界,循环拓展以上三种情况,并实时更新最长回文子串长度
因为遍历的是以每一个字符为中心扩展的情况,因此遍历完字符串,所有情况的子串情况也都考虑到了,时间复杂度O(n^2)
- class Solution {
- public:
- string longestPalindrome(string s) {
-
- string res="";
- int n=s.size();
-
- for(int i=0;i
- {
- int len=1;
- int l=i-1,r=i+1;
- while(l>=0 && s[l]==s[i])
- len++,l--;
- while(r
- len++,r++;
- while(l>=0 && r
- len+=2,l--,r++;
- if(len>res.size())
- res=s.substr(l+1,len);
-
- }
- return res;
- }
-
- };
(2)dp
思路:
- dp[i][j]:表示区间范围[i,j]的子串是否是回文子串,如果dp[i][j]为true,否则为false
- 初始化dp[i][i] = true,因为单个字符自己就是回文串
只考虑s[i]和s[j]相等的情况,因为不相等根本就不可能为回文串(初始化dp全为false,所以只要把所有是回文串的情况标为true即可)
dp是以小范围的状态去更新大范围的状态,因此需要用短子串去更新长子串
dp[i][j]的状态取决于dp[i+1][j-1],如果i和j中间就1个字符,那必然是回文串,即就是j-1-(i+1)+1<2,化简即为j - i < 3,也就是说j - i < 3的情况dp[i][j]必为true
其他情况则用dp[i+1][j-1]来更新
最后遍历所有dp情况,如果dp=true,则更新最长回文子串长度
- class Solution {
- public String longestPalindrome(String s) {
- int n=s.length();
- if(n<2) return s;
-
- boolean[][] dp=new boolean[n][n];
- int maxlen=1,st=0;
-
- for(int i=0;i
- dp[i][i]=true;
-
- for(int j=1;j
- for(int i=0;i
- {
- if(s.charAt(i)==s.charAt(j))
- {
- if(j-i<3) dp[i][j]=true;
- else dp[i][j]=dp[i+1][j-1];
- }
-
- if(dp[i][j] && j-i+1>maxlen)
- {
- st=i;
- maxlen=j-i+1;
- }
- }
-
- return s.substring(st,st+maxlen);
- }
- }
6、三数之和 - 双指针 + 判重

这题难点是:不能出现重复情况
思路:
首先对数组进行升序排序,因为三数之和=0,排序后能更好地去掉不可能为0的方案
遍历数组中每一个数作为第一个数x1
- 如果x1>0,后面的数都比x1大,不可能有=0的方案存在
- 如果遍历到的x1和前一个遍历过的元素值相同,则所生成的方案也是相同的,跳过
- l 和 r 分别指向x1后的最前和最末尾元素,如果指向的三个之和=0则记录方案
- 注意:如果s【l+1】和s【l】值一样,则需要跳过,因为s【l】作为x2的方案之前已经考虑过,而题目要求不能有重复情况,s【r】同理
- (若两个数固定,剩下一个必固定,题目要求不能重复)
- 如果三数之和sum>0,则r--
- 如果sum<0,l++
- class Solution {
- public:
- vector
int>> threeSum(vector<int>& nums) { - vector
int>> res; - int n=nums.size();
- sort(nums.begin(),nums.end());
-
- if(n<3) return res;
-
- for(int i=0;i
- {
- if(nums[i]>0) continue;
- if(i>0&&nums[i]==nums[i-1]) continue;
- int l=i+1,r=n-1;
- while(l
-
- int sum=nums[i]+nums[l]+nums[r];
-
- if(sum==0)
- {
- res.push_back({nums[i],nums[l],nums[r]});
- while(l
1]) l++; //去重 - while(l
-1]) r--; - l++,r--; //若两个数固定,剩下一个必固定,题目要求不能重复,因此移动双指针
-
- }else if(sum>0) r--;
- else l++;
- }
- }
- return res;
- }
- };
7、盛水最多的容器 - 思维 + 双指针

思路:
从两侧枚举板子
因为装水的高度取决于短板
若移动短板,则短板为min(h[i],h[j]),短板有可能变长,水体积可能增加
若移动长板,就算长板更长,也无法改变水的体积,因此水体积减小(间距变小),因此绝对不能移动长板
- class Solution {
- public:
- int maxArea(vector<int>& h) {
-
- // 从两侧枚举板子
- // 因为装水的高度取决于短板
- // 若移动短板,则短板为min(h[i],h[j]),短板有可能变长,水体积可能增加
- // 若移动长板,就算长板更长,也无法改变水的体积,因此水体积减小(间距变小),因此绝对不能移动长板
- int i=0,j=h.size()-1;
- int res=0;
-
- while(i
- {
- res= h[i]>h[j]?
- max(res,(j-i)*h[j--]):max(res,(j-i)*h[i++]);
- }
- return res;
- }
- };
8、电话号码的字母组合 - dfs + 组合

思路:
【leetcode学习计划】算法入门(14 / 14)完结!_leetcode算法学习计划_Roye_ack的博客-CSDN博客
这题就是dfs组合问题的升级版
根据题意,digits长度就是每个组合的长度,我们可以枚举每一个位置的数字
用哈希表存每个数字对应的字母
如果每个位置都枚举完,则将该种情况存入答案
- class Solution {
- public:
- vector
tele={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"}; - vector
res; - string t;
-
- void dfs(int pos,string digits)
- {
- if(pos==digits.size())
- {
- res.push_back(t);
- return;
- }
- int num=digits[pos]-'0';
- for(int i=0;i
size();i++) - {
- t.push_back(tele[num][i]);
- dfs(pos+1,digits);
- t.pop_back();
- }
- }
-
- vector
letterCombinations(string digits) { - if(digits.size()==0) return res;
- dfs(0,digits);
- return res;
- }
- };
9、删除链表的倒数第N个节点 - 链表 + 快慢指针 / 栈

(1)暴力 计算链表长度
移动到要删除的节点的前一个,然后将该节点指向待删除节点的下一个,实现节点删除
- class Solution {
- public:
- ListNode* removeNthFromEnd(ListNode* head, int n) {
- ListNode* dummy=new ListNode(0);
- dummy->next=head;
- ListNode* cur=head;
- int len=0;
- while(cur!=nullptr)
- {
- len++;
- cur=cur->next;
- }
-
- cur=dummy;
- for(int i=0;i
- {
- cur=cur->next;
- }
- cout<
val< - cur->next=cur->next->next;
- return dummy->next;
- }
- };
(2)快慢指针
- 定义快指针q和慢指针p,两者初始同时指向虚拟节点dummy
- 先移动快指针q使pq间隔n个元素,随后同时移动pq指针,直至q指向链表末尾null,此时,p指针的下一个节点就是待删除节点
-
- class Solution {
- public ListNode removeNthFromEnd(ListNode head, int n) {
- ListNode dummy=new ListNode(0);
- dummy.next=head;
- ListNode p=dummy,q=dummy;
- for(int i=0;i
1;i++) - q=q.next;
- while(q!=null)
- {
- p=p.next;
- q=q.next;
- }
- p.next=p.next.next;
- return dummy.next;
-
- }
- }
(3)栈
删除倒数第n个节点,可以利用栈的特性,让所有元素都入栈,然后扔出栈中n个节点,此时栈顶元素就是待删除的节点的前一个,然后再执行删除节点操作
- class Solution {
- public:
- ListNode* removeNthFromEnd(ListNode* head, int n) {
- ListNode* dummy = new ListNode(0, head);
- stack
stk; - ListNode* cur = dummy;
- while (cur) {
- stk.push(cur);
- cur = cur->next;
- }
- for (int i = 0; i < n; ++i) {
- stk.pop();
- }
- ListNode* prev = stk.top();
- prev->next = prev->next->next;
- ListNode* ans = dummy->next;
- delete dummy;
- return ans;
- }
- };
10、有效的括号 - 暴力 + 栈 + 哈希表

(1)暴力+栈
- class Solution {
- public boolean isValid(String s) {
- if(s.length()%2==1) return false;
- Deque
stk=new LinkedList<>(); - for(int i=0;i
length();i++) - {
- char c=s.charAt(i);
- if(c=='('||c=='['||c=='{')
- stk.push(c);
- else if(c==')')
- {
- if(stk.isEmpty()||stk.peek()!='(') return false;
- stk.pop();
- }else if(c==']')
- {
- if(stk.isEmpty()||stk.peek()!='[') return false;
- stk.pop();
- }else if(c=='}')
- {
- if(stk.isEmpty()||stk.peek()!='{') return false;
- stk.pop();
- }
- }
- if(!stk.isEmpty()) return false;
- return true;
- }
- }
(2)哈希表+栈
- class Solution {
- public:
- bool isValid(string s) {
- int n=s.size();
- if(n%2) return false;
-
- stack<char> stk;
- unordered_map<char,char> mp={
- {')','('},
- {']','['},
- {'}','{'}
- };
-
- for(int i=0;i
- {
- if(mp.count(s[i]))
- if(stk.empty()||mp[s[i]]!=stk.top())
- return false;
- else stk.pop();
- else stk.push(s[i]);
- }
- return stk.empty();
- }
- };
-
相关阅读:
无法启动此程序,因为计算机中丢失msvcp140.dll的修复方法与解决方法
cesium 实体无法拾取
认真过一遍webpack
什么是单片机?聊聊它的历史
数据分析和可视化平台:Splunk Enterprise for mac v9.1.1激活版 兼容m1
Java通过javacv获取视频、音频、图片等元数据信息(分辨率、大小、帧等信息)
史上最简单的Terraform教程不浪费时间
【ClickHouse 基础】
这个Spring Security登录插件牛啊,验证码、小程序、OAuth2都能快速接入
【Linux】Docker安装
-
原文地址:https://blog.csdn.net/weixin_61639349/article/details/132964391