LeetCode 刷题笔记---(五)
LeetCode 刷题笔记---(五)
今天刷hot100
ID:35
二分查找,找不到就按顺序插入
简单的练练手
answer:
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
int i=0;
int j=nums.size();
int res=0;
while(i<j){
int mid=(i+j)/2;
if(mid==i)break;
int privot=nums[mid];
if(target>privot){
i=mid;
}else if(target<privot){
j=mid;
}else return mid;
}
if(target>nums[i])return j;
else return i;
}
};
ID:34
上一题的进阶版,二分查找,要求返回target的最早下标,最迟下标
思路历程:
一开始想的是,二分查找,然后找到后,将结果存入vector res,结果没考虑到找到后下标怎么变化。
后来想通了,简单一点,找到后就break;
出循环后分两种情况:
-
如果l==mid,说明是循环条件不满足退出的
判断nums[i]==target,因为j是一定会被遍历到的,i不一定,所以要判断,如果符合,就返回两个i
如果不符合说明没找到,返回{-1,-1}
-
如果i !=mid,说明是找到了退出的,那么左右指针初始化为mid,然后分别往左往右,返回左右指针
answer:
class Solution {
public:
vector<int> searchRange(vector<int>& nums, int target) {
int i=0;
int j=nums.size();
int mid;
if(nums.empty())return {-1,-1};
while(i<=j){
mid=(i+j)/2;
if(mid==i)break;
int privot =nums[mid];
if(target>privot){
i=mid;
}else if(target<privot){
j=mid;
}else{
break;
}
}
int l=-1,r=-1;
if(i==mid){
if(nums[i]==target){
return{i,i};
}else{
return{-1,-1};
}
}
l=r=mid;
while(l>=0&&nums[l]==target)l--;
while(r<nums.size()&&nums[r]==target)r++;
return{l+1,r-1};
}
};
ID:64
和之前的路径选优差不多,也是DP的思想
思路历程:
先遍历第一行第一列,初始化第一行、第一列的结果
然后判断是否为单行单列,是的话可以直接返回结果
如果不是,就一层层遍历下去,当前格子的最优解=min(左边的最优解,上面的最优解)+当前格子的值
answer:
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int m=grid.size();
int n=grid[0].size();
vector<vector<int>> map;
map=grid;
int i=1,j=1;
while(i<m){
map[i][0]=map[i-1][0]+grid[i][0];
i++;
}
while(j<n){
map[0][j]=map[0][j-1]+grid[0][j];
j++;
}
if(m==1)return map[0][n-1];
if(n==1)return map[m-1][0];
i=j=1;
while(i<m){
j=1;
while(j<n){
map[i][j]=min(map[i-1][j],map[i][j-1])+grid[i][j];
j++;
}
i++;
}
return map[m-1][n-1];
}
};
BFS会更好吗?其实不一定,斜着一层层遍历,不一定会比行列的遍历更快
ID:230
思路历程:
一开始没看到是二叉搜索树,看到左孩子<父亲节点<右孩子 才记起来
然后再想DFS,很惭愧。。。一开始一直想用栈
后来发现用函数递归巨快无比。。。
answer:
class Solution {
public:
void dfs(TreeNode*tmp){
if(tmp->left)dfs(tmp->left);
res.push_back(tmp->val);
if(tmp->right)dfs(tmp->right);
}
vector<int> res;
int kthSmallest(TreeNode* root, int k) {
dfs(root);
return res[k-1];
}
};
ID:238
思路历程:
。。。不要使用除法。。。
不太会,看题解了
看到了前缀积和后缀积,有了点想法
就是在第一次遍历的时候,开个数组记录前n个积,开个数组记录后n个积
然后第二次遍历就可以实现前缀积与后缀积相乘得到结果
answer:
class Solution {
public:
vector<int> productExceptSelf(vector<int>& nums) {
int n=nums.size();
if(n==2)return{nums[1],nums[0]};
vector<int>head(n);
vector<int>tail(n);
vector<int>res(n);
int i=1,j=n-1;
head[0]=nums[0];tail[n-1]=nums[n-1];
while(i<n-1){
head[i]=head[i-1]*nums[i];
tail[j-i]=tail[j-i+1]*nums[j-i];
i++;
}
i=1;
res[0]=tail[1];res[n-1]=head[n-2];
while(i<n-1){
res[i]=head[i-1]*tail[i+1];
i++;
}
return res;
}
};
有一说一,第一次遇到前缀的概念,挺新颖的,让我想起了字节一面的那道题目
其实只要每行数组取出最大前缀和,然后记录下标,每次继续下去要成为负数就去其他路加回正的,
如果加不回来,就换条路先走
每条路到达最大值后就停下来,这条路的使命就完成了
ID:72
思路历程:
一开始想着先判断字符长度,如果相等,就判断相同下标是否一致,然后总数-一致数(不对的)
然后不相等的情况下,拿短的字符串在长字符串中寻找,如果顺序一致可以减去一致数
但是这个找到顺序一致有点难啊,
主要是find没搞清楚返回了什么,没找到的话会返回一个很大的数
然后字符串不同的通过了一些,相同的又不会了
看了题解,居然是DP问题。。。
(有点难,需要缓一缓)
ID:234
简单的回文判断(链表)
我觉得下次可以直接用简单的想法,没必要想很多奇奇怪怪的数据结构
看题解的时候可以欣赏,但是做题的时候要先保证能做出来
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector<int> all;
ListNode* tmp=head;
if(!head->next)return true;
int count=0;
while(tmp){
count++;
all.push_back(tmp->val);
tmp=tmp->next;
}
int i=0;
while(i<=count/2){
if(all[i]!=all[count-i-1])return false;
i++;
}
return true;
}
};
有的用递归做的,可以减少空间。。。有点看不懂代码,虽然能理解一点
还有一种快慢指针的,快指针是慢指针的两倍速,然后到结尾了,慢指针刚好到中间
然后中间开始反转链表,然后快指针从尾部,头指针从头部遍历并判断
ID:84
思路历程:
很难的一道DP题,虽然知道很多时候该怎么选择,但是有些样例就是考虑不到,关于下一块到来时,我要考虑的有:
-
要不要加上这一块(过去的大小和接收这块后的大小)
这里的接受这块后的大小,是由最小块决定的?是但是范围不一样,最小块也不一样
i是遍历的右指针,head是左指针,一般来说只有重新开始的情况要变化
但是会有问题,就是没有重新开始,但左指针移动会使结果变大
如12345,我的左指针从2开始到4
2*3>4 && 2*3>2*2,所以左指针没动,所以问题在于,如果这块是5,他也不会动,至少我的方案是这样,但其实应该动了,因为2*3=3*2,应该左指针后移了因为这样可以提高短板
-
要不要重新开始(这块太大了,比我之前的res都大太多了)
看题解吧
。。。居然不是DP,第一次见到单调栈
真的花了我好长时间,我是第二天起来才写好的
使用单调栈的过程中记得注意,入栈的时候一定要递增而不是非递减,
出栈的时候遇到小于自己的才停下(不能相等)
class Solution {
public:
int largestRectangleArea(vector<int>& heights) {
int n=heights.size();
int i=1;
int res=heights[0];
vector<int> left(n);
vector<int> right(n);
if(n==1)return heights[0];
if(n==2)return max(max(heights[0],heights[1]),min(heights[0],heights[1])*2);
int head=0;
stack<pair<int,int>> stk;
stk.push({heights[0],0});
left[0]=-1;
right[n-1]=n;
int nowleft=-1;
while(i<n){
auto now=stk.top();
if(now.first<heights[i]){
stk.push({heights[i],i});
left[i]=now.second;
}else{
while(!stk.empty()){
if(stk.top().first>=heights[i]){
stk.pop();
}else break;
}
if(!stk.empty()){
left[i]=stk.top().second;
}else{
left[i]=-1;
}
stk.push({heights[i],i});
}
i++;
}
while(!stk.empty())stk.pop();
i--;
stk.push({heights[i],i});
while(i--){
auto now=stk.top();
if(now.first<heights[i]){
stk.push({heights[i],i});
right[i]=now.second;
}else{
while(!stk.empty()){
if(stk.top().first>=heights[i]){
stk.pop();
}else break;
}
if(!stk.empty()){
right[i]=stk.top().second;
}else{
right[i]=n;
}
stk.push({heights[i],i});
}
}
for(i=0;i<n;i++){
int m=(right[i]-left[i]-1)*heights[i];
res=max(res,m);
}
return res;
}
};
ID:72 我下次再补吧