leecode142 环形链表II
给定一个链表,返回链表开始入环的第一个节点。 如果链表无环,则返回 null。
为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
说明:不允许修改给定的链表。
示例 1:
输入:head = [3,2,0,-4], pos = 1
输出:tail connects to node index 1
解释:链表中有一个环,其尾部连接到第二个节点。
思路:先快慢指针判断是否有环,然后从头一个新的指针,和快指针(慢指针)同时走,相遇的地方既是交点
快慢一起:2(a+x)=a+mb+x —>a=mb-x
快指针再走a步的话,a+mb+x+a=a+2mb(代入了上式),正好走a步到达环的入口
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode(int x) : val(x), next(NULL) {}
* };
*/
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
if(head==nullptr){return NULL;}
ListNode* slow=head;
ListNode* fast=head;
bool hascycle=false;
while(fast->next&&fast->next->next){
slow=slow->next;
fast=fast->next->next;
if(slow==fast){
hascycle=true;
break;
}
}
if(hascycle){
ListNode* det=head;
while(det!=slow){
det=det->next;
slow=slow->next;
}
return det;
}
else{
return NULL;
}
}
};
leecode152 乘积最大子数组
给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。
示例 1:
输入: [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
思路: 求最大值,可以看成求被0拆分的各个子数组的最大值。
当一个数组中没有0存在,则分为两种情况:
1.负数为偶数个,则整个数组的各个值相乘为最大值;
2.负数为奇数个,则从左边开始,乘到最后一个负数停止有一个“最大值”,从右边也有一个“最大值”,比较,得出最大值。
class Solution {
public:
int maxProduct(vector<int>& nums) {
int a=1;
int max=nums[0];
for(auto num:nums){
a=a*num;
if(a>max){max=a;}
if(num==0){a=1;}
}
a=1;
for(int i=nums.size()-1;i>=0;i--){
a=a*nums[i];
if(a>max){max=a;}
if(nums[i]==0){a=1;}
}
return max;
}
};
leecode84 柱形图中的最大面积(hard)
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
//维护一个单调递增栈来寻找当前柱前面和后面比当前小的柱子,由此确定宽度。
//最终找最大面积即可
//补0是为了让所有元素都出栈被计算一次。
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
stack <int> s;
heights.insert(heights.begin(), 0);
heights.push_back(0);
int n=heights.size();
vector<int> area(n+1);
for(int i=0;i<n;i++){
while(!s.empty()&&heights[s.top()]>heights[i]){
int h=heights[s.top()];
int curr=s.top();
s.pop();
int right=i;
int left=s.top();
area[curr]=h*(right-left-1);
}
s.push(i);
}
int max_area=0;
for(int i=0;i<area.size();i++){
if(area[i]>max_area){
max_area=area[i];
}
}
return max_area;
}
};
leecode 124. 二叉树中的最大路径和(hard)
给定一个非空二叉树,返回其最大路径和。
本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列。该路径至少包含一个节点,且不一定经过根节点。
示例 1:
输入: [1,2,3]
1
/ \
2 3
输出: 6
示例 2:
输入: [-10,9,20,null,null,15,7]
-10
/
9 20
/
15 7
输出: 42
//O(N) O(N)
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int maxsum=INT_MIN;
int maxPathSum(TreeNode* root) {
max_path(root);
return maxsum;
}
// 递归计算左右子节点的最大贡献值
// 只有在最大贡献值大于 0 时,才会选取对应子节点
int max_path(TreeNode* root){
if(root==NULL){return 0;}
int left=max(max_path(root->left),0);
int right=max(max_path(root->right),0);
//节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值
int root_pathsum=left+right+root->val;
//更新最大值
maxsum=max(maxsum,root_pathsum);
//递归每一层返回每个节点的最大贡献值
return root->val+max(left,right);
}
};
leecode16 最接近的三数之和(medium)
给定一个包括 n 个整数的数组 nums 和 一个目标值 target。找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。假定每组输入只存在唯一答案。
示例:
输入:nums = [-1,2,1,-4], target = 1
输出:2
解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
//三指针 固定一个,移动另外两个
//O(N)
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
int closestnum=nums[0]+nums[1]+nums[2];
for(int i=0;i<nums.size()-2;i++){
int l=i+1,h=nums.size()-1;
while(l<h){
int threenum=nums[i]+nums[l]+nums[h];
if(abs(target-threenum)<abs(target-closestnum)){
closestnum=threenum;
}
if(threenum==target){
return target;
}
else if(threenum<target){
l++;
}
else{
h--;
}
}
}
return closestnum;
}
};
leetcode139 单词拆分(medium)
给定一个非空字符串 s 和一个包含非空单词列表的字典 wordDict,判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。
说明:
拆分时可以重复使用字典中的单词。
你可以假设字典中没有重复的单词。
示例 1:
输入: s = “leetcode”, wordDict = [“leet”, “code”]
输出: true
解释: 返回 true 因为 “leetcode” 可以被拆分成 “leet code”。
输入: s = “catsandog”, wordDict = [“cats”, “dog”, “sand”, “and”, “cat”]
输出: false
思路:以str(begin, end)来表示str的子字符串,从前往后遍历,有多少种呢?
end=1, begin=0;
end=2, begin=0/1;
end=3, begin=0/1/2;
…
end=n-1, begin=0/1/…/n-2;
一共是(n-1)n/2种,遍历一遍是O(n^2)的时间复杂度
这么多种可能的子字符串,逐次的去判断它们是否与字典中的某个字符串相同,如果相同了,就在end的位置标记相同(true),end的位置一定在begin之后(begin<end),那么要查询str(begin, end),begin前面的位置一定要是true才行,意味着已经寻到了一个或者一些匹配字典的子字符串,那么就要记录是否寻得的状态。
既然要寻找,最开始的状态就要是true,也就是dp[0]=true,其他位为false,一旦寻得,end为的状态变为true,继续往下寻找,为了避免漏掉某些情况,每次的begin都是从0开始的。
//O(N^2)
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
if(s.empty()|| wordDict.empty()){return false;}
set<string> word;
int n=s.size();
for(int i=0;i<wordDict.size();i++){
word.insert(wordDict[i]);
}
vector<bool> dp(n+1,false);
dp[0]=true;
for(int end=1;end<=n;end++){
for(int begin=0;begin<end;begin++){
if(dp[begin]&&word.find(s.substr(begin,end-begin))!=word.end()){
dp[end]=true;
break;
}
}
}
return dp[n];
}
};
leetcode 718:最长重复子数组(medium)
给两个整数数组 A 和 B ,返回两个数组中公共的、长度最长的子数组的长度。
示例 1:
输入:
A: [1,2,3,2,1]
B: [3,2,1,4,7]
输出: 3
解释:
长度最长的公共子数组是 [3, 2, 1]。
1.动态规划 (注意与最长子序列的区别,连续和不连续的区别)
当A [i]==B[j]的时候都是 dp[i][j]=dp[i-1][j-1]+1;
但是不相同时,子序列:dp[i][j]=max(dp[i-1][j],dp[i][j-1])要注意一下。
时间复杂度: O(N M),空间O(NM)。
空间复杂度: O(N \times M)O(N×M)。
class Solution {
public:
int findLength(vector<int>& A, vector<int>& B) {
int a_length=A.size(),b_length=B.size();
if(a_length==0 || b_length==0){return 0;}
int dp[a_length+1][b_length+1];
for(int i=0;i<a_length;i++){
dp[i][0]=0;
}
for(int j=0;j<b_length;j++){
dp[0][j]=0;
}
int res=0;
for(int i=1;i<=a_length;i++){
for(int j=1;j<=b_length;j++){
if(A[i-1]==B[j-1]){
dp[i][j]=dp[i-1][j-1]+1;
res=max(res,dp[i][j]);
}
else dp[i][j]=0;
}
}
return res;
}
};