记忆化搜索题目

现在前面

找实习期间刷题的时候总会遇到特别变态刷不出来的题目,赛后看了大佬们的评价,很多人大佬是使用bfs+记忆化搜索硬搜,换取部分成绩的(例如A了30%),为了混这部分分,这里记录一下记忆化搜索的题目,题解,代码。

1 记忆化搜索

定义:
把计算过的结果存下来,减少计算量

作用:
用空间换时间,减少递归

2 典型题目

2.1 leetcode斐波那契数列

题解:
太经典了,就不写了。

代码:

class Solution {
public:
    int fib(int n) {
        int F[100000]={0,1,1,2};
        for(int i=4;i<=n;i++){
            F[i]=F[i-1]+F[i-2];
        }

        return F[n];
    }
};

2.2 leetcode硬币收集

题解:
1.核心实现代码

  if(dp[i-coins[j]]+1<Min){
      Min=dp[i-coins[j]]+1;
      dp[i]=Min;
  }

2.特殊情况
当amount=0时

if(amount==0){
    return 0;
}

代码:

#include <algorithm>
using namespace std;
class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        //sort(coins);
        if(amount==0){
            return 0;
        }
        auto dp=vector<int>(amount+1,0);
        
        int length=coins.size();

        for(int i=0;i<=amount;i++){
            int Min=9999;
            for(int j=0;j<length;j++){
                if (coins[j]==i){
                    dp[i]=1;
                    break;
                }

                else if(coins[j]>i){
                    continue;
                }
                else if(coins[j]<i){
                    if(dp[i-coins[j]]==0)
                        continue;
                    else{
                        if(dp[i-coins[j]]+1<Min){
                            Min=dp[i-coins[j]]+1;
                            dp[i]=Min;
                        }
                    }
                        
                }
            }
        }
        if(dp[amount]==0)
            return -1;

        return dp[amount];
    }
};

3 配合bfs/dfs的记忆化搜索

bfs经典

#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <queue>
using namespace  std;
int maze[200][200];
int ans;
int xdir[4]={0,0,1,-1};
int ydir[4]={1,-1,0,0};
int m,n;

/*
4 4
1 1 2 2
1 2 2 2
3 1 1 1
3 3 3 3
 */

pair<int,int> findmaze(int target){
    pair<int,int> res;
    res.first=-1;
    res.second=-1;
    for(int i=0;i<m;i++)
        for(int j=0;j<n;j++){
            if(maze[i][j]==target){

                res.first=i;
                res.second=j;
                return res;
            }
        }
    return res;
}

void dfs(int x,int y,int target){
    if(maze[x][y]!=target){
        return;
    }
    maze[x][y]=-1;
    for(int i=0;i<4;i++){
        int new_x=x+xdir[i];
        int new_y=y+ydir[i];
        if(maze[new_x][new_y]!=target){
            continue;
        }
        dfs(new_x,new_y,target);
    }
}

void bfs(int x,int y,int target){
    queue<pair<int,int>> qu;
    qu.push({x,y});

    while(!qu.empty()){

        auto t=qu.front();
        qu.pop();
        int t_x=t.first;
        int t_y=t.second;
        maze[t_x][t_y]=-1;
        for(int i=0;i<4;i++) {
            int new_x = t_x + xdir[i];
            int new_y = t_y + ydir[i];
            if(maze[new_x][new_y]!=target&&new_x<0&&new_y<0&&new_x>=m&&new_y>=n){
                continue;
            }
            if(maze[new_x][new_y]==target){
                qu.push({new_x,new_y});
            }
        }

    }

}



void input(){

    cin>>m>>n;
    int sub=int('1')-1;
    for(int i=0;i<m;i++){
        string a;
        cin>>a;
        for(int j=0;j<n;j++){
            maze[i][j]=int(a[j])-sub;
        }
    }

}


int main(){

    input();
    ans=0;
    int i=1;
    while(i<=3){
        auto start=findmaze(i);
        if(start.first<0) {
            i++;
        }
        else{
            bfs(start.first,start.second,i);
            ans++;
        }
    }
    cout<<ans;
    return 0;

}

记忆化搜索=搜索的形式+动态规划的思想。
记忆化搜索的思想是,在搜索过程中,会有很多重复计算,如果我们能记录一些状态的答案,就可以减少重复搜索量。

DP是从下向上求解的,而记忆化搜索是从上向下的,因为它用到了递归。

模板
c++

map<string,int> isVisit;


int minDistanceExec(string word1,string word2){
    //3.判断时候需要返回结果已经进行一些剪枝(特殊情况)


    //已经找到过答案就直接返回
	if (isVisit.count(hashVal)) {
		return isVisit[hashVal];
	}

    //4.找不到进行计算,继续调用记忆化搜索函数,得出结果
    int ans=0;

    isVisit[hashVal]=ans;
    return ans;
}


int minDistance(string word1, string word2) { //记忆化搜索函数调用者

    //1.进行预处理


    //2.开始调用记忆化搜索函数
    return minDistanceExec(word1,word2);
}

leetcode583

题解:
1.搜索思路,dfs

if (word1[length1 - 1] == word2[length2 - 1]) {
	ans = minDistanceExec(word1.substr(0, length1 - 1), word2.substr(0, length2 - 1));
}
else {
	int a = minDistanceExec(word1.substr(0, length1 - 1), word2);
	int b = minDistanceExec(word1, word2.substr(0, length2 - 1));
	ans = min(a, b)+1;
}

2.特殊情况

 if(word1.length()==0)
     return word2.length();
 if(word2.length()==0)
     return word1.length();

3.记忆化搜索

string hashVal = word1 + "|" + word2;
if (isVisit.count(hashVal)) {
	return isVisit[hashVal];
}

代码(1306个case a了1304个,值了)

class Solution {
public:
map<string, int> isVisit;


int minDistanceExec(string word1, string word2) {
	//3.判断时候需要返回结果已经进行一些剪枝(特殊情况)
	if (word1.length() == 0)
		return word2.length();
	if (word2.length() == 0)
		return word1.length();

	//已经找到过答案就直接返回
	string hashVal = word1 + "|" + word2;
	if (isVisit.count(hashVal)) {
		return isVisit[hashVal];
	}

	//4.找不到进行计算,继续调用记忆化搜索函数,得出结果
	int ans = 0;
	int length1 = word1.length();
	int length2 = word2.length();
	if (word1[length1 - 1] == word2[length2 - 1]) {
		ans = minDistanceExec(word1.substr(0, length1 - 1), word2.substr(0, length2 - 1));
	}
	else {
		int a = minDistanceExec(word1.substr(0, length1 - 1), word2);
		int b = minDistanceExec(word1, word2.substr(0, length2 - 1));
		ans = min(a, b)+1;
	}

	isVisit[hashVal] = ans;
	return ans;
}


int minDistance(string word1, string word2) { //记忆化搜索函数调用者

	//1.进行预处理
	//2.开始调用记忆化搜索函数
	return minDistanceExec(word1, word2);
}

};

678. 有效的括号字符串

题解:
1.搜索思路,记录左右括号的状态
出现左括号或者“”(把“”当做左括号),就左括号+1
出现左括号或者“”(把“”当做右括号),就右括号+1
出现“*”,(当没有)左右括号不变

核心代码

	if (lastchar == '(' || lastchar == '*') { //*可以当右括号用
		ans = ans || checkValidStringExc(s, nowIndex - 1, left + 1, right);
	}
	if (lastchar == ')' || lastchar == '*') {
		ans = ans || checkValidStringExc(s, nowIndex - 1, left, right + 1);
	}
	if (lastchar == '*') {
		ans = ans || checkValidStringExc(s, nowIndex - 1, left, right);
	}

2.特殊情况
nowIndex==-1时说明已经遍历完了
由后往前遍历,如果左括号多余右括号,必然有左括号无右括号匹配 (如“(()”)

if (nowIndex == -1) {
	return left == right;
}
if (left>right) {
	return false;
}

代码(a了)

class Solution {
public:
map<int, bool> isVisited;
int myhash(int a, int b, int c) {
	return (a << 20) + (b << 10) + c;
}

bool checkValidStringExc(string s, int nowIndex, int left, int right) {
	if (nowIndex == -1) {
		return left == right;
	}
	if (left>right) {
		return false;
	}


	int hashnum = myhash(nowIndex, right, left);
	if (isVisited.count(hashnum)) {
		return isVisited[hashnum];
	}


	bool ans = false;
	char lastchar = s[nowIndex];
	if (lastchar == '(' || lastchar == '*') { //*可以当右括号用
		ans = ans || checkValidStringExc(s, nowIndex - 1, left + 1, right);
	}
	if (lastchar == ')' || lastchar == '*') {
		ans = ans || checkValidStringExc(s, nowIndex - 1, left, right + 1);
	}
	if (lastchar == '*') {
		ans = ans || checkValidStringExc(s, nowIndex - 1, left, right);
	}



	isVisited[hashnum] = ans;

	return ans;
}

bool checkValidString(string s) {
	return checkValidStringExc(s, s.length() - 1, 0, 0);
}



};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值