1.dp
class Solution {
public:
int minPathSum(vector<vector<int>>& grid) {
int n=grid.size();
if(!n) return 0;
int m=grid[0].size();
vector<vector<int>> dp=vector<vector<int>>(n,vector<int>(m,INT_MAX));
for(int i=0;i<n;i++)
for(int j=0;j<m;j++){
if(!i&&!j) dp[i][j]=grid[i][j];
else{
if(i) dp[i][j]=min(dp[i][j],dp[i-1][j]+grid[i][j]);//看看从上边走来的状态
if(j) dp[i][j]=min(dp[i][j],dp[i][j-1]+grid[i][j]);//看看从左边走来的状态
}
}
return dp[n-1][m-1];
}
};
思路
- 动态规划,每个位置只可能从上或者左过来。
2.栈
class Solution {
public:
string simplifyPath(string path) {
int n=path.size();
string res,name;
if(path.back()!='/') path+='/';//加这个是为了统一格式,都以/结尾
for(auto c:path){
if(c!='/'){
name+=c;//装名字
}else{
if(name==".."){//回退
while(res.size()&&res.back()!='/') res.pop_back();//吐名字
if(res.size()) res.pop_back();//吐/
}else if(name!="."&&name!=""){//.和空被忽略
res+='/'+name;//装进/+名字
}
name.clear();
}
}
if(res.empty()) res+='/';
return res;
}
};
3.脑筋急转弯
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
int N=matrix.size();
int M=matrix[0].size();
int st1=0,st2=0;//用于判断第0行和第0列是否需要设0
for(int i=0;i<N;i++){
if(matrix[i][0]==0){
st1=1;
break;
}
}
for(int i=0;i<M;i++){
if(matrix[0][i]==0){
st2=1;
break;
}
}
for(int i=1;i<N;i++){
for(int j=1;j<M;j++){//从[1][1]开始找一旦有0则记录在对应行
//和对应列的头部也就是第0行和第0列
if(matrix[i][j]==0){
matrix[i][0]=0;
matrix[0][j]=0;
}
}
}
for(int i=1;i<N;i++){
if(matrix[i][0]==0){
for(int j=0;j<M;j++){
matrix[i][j]=0;
}
}
}
for(int i=1;i<M;i++){
if(matrix[0][i]==0){
for(int j=0;j<N;j++){
matrix[j][i]=0;//i是列噢
}
}
}
if(st1){//最后才处理第0行和第0列,因为前面拿来装东西了,脏了,所以留最后更新
for(int i=0;i<N;i++){
matrix[i][0]=0;
}
}
if(st2){
for(int i=0;i<M;i++){
matrix[0][i]=0;
}
}
}
};
思路
- 先看第一行第一列是否要刷0,记录后,就遍历,看看哪行哪列需要刷0,用的话记在相应的第一行和第一列的位置。
4.二分
class Solution {
public:
bool searchMatrix(vector<vector<int>>& matrix, int target) {
int n=matrix.size(),m=matrix[0].size();
if(n==0||m==0) return false;
int l=0,r=n*m-1;
while(l<r){
int mid=(l+r)>>1;
if(matrix[mid/m][mid%m]>=target){//记住一维转二维的公式[mid/m][mid%m]
r=mid;
}else l=mid+1;
}
return matrix[r/m][r%m]==target;
}
};
5.脑筋急转弯
class Solution {
public:
void sortColors(vector<int>& nums) {
for(int i=0,j=0,k=nums.size()-1;i<=k;){//j是0和1分界,i是遍历到哪里,k是2和其他的边界
//当i和k重合再过一步就可以保证0、1、2分完
if(nums[i]==0){
swap(nums[j],nums[i]);
j++,i++;
}else if(nums[i]==2){
swap(nums[i],nums[k]);
k--;
}else i++;
}
}
};
6.dfs
class Solution {
public:
vector<vector<int>> res;
vector<int> path;
vector<vector<int>> combine(int n, int k) {
dfs(n,k,1);
return res;
}
void dfs(int n,int k,int idx){
if(!k){
res.push_back(path);
return;
}
for(int i=idx;i<=n;i++){//idx是为了保证从前往后,好马不吃回头草的顺序,保证不重不漏
path.push_back(i);
dfs(n,k-1,i+1);
path.pop_back();
}
}
};
7.位运算
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res;
int n=nums.size();
for(int i=0;i<1<<n;i++){//n位二进制
vector<int> path;
for(int j=0;j<n;j++){//看每一位是0还是1
if(i>>j&1){//相应位为1就表示相应位的数字要
path.push_back(nums[j]);
}
}
res.push_back(path);
}
return res;
}
};
8.dfs
class Solution {
public:
bool exist(vector<vector<char>>& board, string word) {
for(int i=0;i<board.size();i++)
for(int j=0;j<board[i].size();j++){
if(dfs(board,word,0,i,j)) return true;
}
return false;
}
int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
bool dfs(vector<vector<char>>& board,string& word,int c,int x,int y){
if(board[x][y]!=word[c]) return false;
if(c==word.size()-1){
return true;
}
char t=board[x][y];
board[x][y]='.';//表示用过
for(int i=0;i<4;i++){
int a=x+dx[i],b=y+dy[i];
if(a<0||a>=board.size()||b<0||b>=board[0].size()||board[a][b]=='.'){//边界
continue;
}
if(dfs(board,word,c+1,a,b)) return true;
}
board[x][y]=t;//恢复现场
return false;
}
};
9.栈
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
int k=0;
for(auto x:nums){
if(k<2||nums[k-1]!=x||nums[k-2]!=x){//只要不和前俩重复就装
nums[k++]=x;
}
}
return k;
}
};
10.二分
class Solution {
public:
bool search(vector<int>& nums, int target) {
if(nums.empty()) return false;
int n=nums.size()-1;//画图知道图像是两段以nums[0]为分界线的
while(n>=0&&nums[n]==nums[0]) n--;//把第二段的nums[0]都去掉,
//因为如果等于这个值两端都有就无法判断在哪段了
if(n<0) return nums[0]==target;
int l=0,r=n;
while(l<r){
int mid=(l+r+1)/2;
if(nums[mid]>=nums[0]) l=mid;//找第一段的尾
else r=mid-1;
}
if(nums[0]<=target) r=l,l=0;//在第一段
else l=l+1,r=n;//在第二段
while(l<r){
int mid=(l+r)/2;
if(nums[mid]>=target) r=mid;
else l=mid+1;
}
return nums[r]==target;
}
};