zoukankan      html  css  js  c++  java
  • leetcode 深搜广搜

    遍历整个grid数组,当发现有1的时候,就把和这个1连成片的1都置为0,并增加一个计数。最后返回这个计数。

    广搜,但这个代码通不过测试,栈溢出。

    复制代码
    class Solution {
    public:
        void bfs(vector<vector<char>>& grid,int i,int j){
            if(i<0||j<0||i>=grid.size()||j>=grid[0].size()) return;
            if(grid[i][j]=='0') return;
            //标记为以及记录过
            grid[i][j]=='0';
            bfs(grid,i+1,j);
            bfs(grid,i-1,j);
            bfs(grid,i,j+1);
            bfs(grid,i,j-1);
        }
        int numIslands(vector<vector<char>>& grid) {
            int ans=0;
            for(int i=0;i<grid.size();i++){
                for(int j=0;j<grid[0].size();j++){
                    if(grid[i][j]=='0') continue;
                    //当为”1“时
                    ans++;
                    bfs(grid,i,j);
                }
            }
            return ans;
        }
    };
    复制代码

    解法2:

    深搜(DFS) 。 这个题也是《挑战程序设计》的第一个深搜的题。

    思路:与《挑战程序设计》相同。只不过这个题是要遍历上下左右四个方向,而《挑战程序设计》是8个方向。

    复制代码
    class Solution {
    public:
        void dfs(vector<vector<char>>& grid,int i,int j){
            int nr = grid.size();
            int nc = grid[0].size();
            grid[i][j] = '0';
            if(i-1>=0 && grid[i-1][j]=='1') dfs(grid,i-1,j);
            if(i+1<nr && grid[i+1][j]=='1') dfs(grid,i+1,j);
            if(j-1>=0 && grid[i][j-1]=='1') dfs(grid,i,j-1);
            if(j+1<nc && grid[i][j+1]=='1') dfs(grid,i,j+1);
        }
        int numIslands(vector<vector<char>>& grid) {
            int nr = grid.size();
            if(!nr) return 0;
            int nc = grid[0].size();
            int isLand = 0;
            for(int i=0;i<nr;i++){
                for(int j=0;j<nc;j++){
                    if(grid[i][j]=='1'){
                        dfs(grid,i,j);
                        isLand++;
                    }
                }
            }
            return isLand;
        }
    };
    复制代码

    复制代码
    class Solution {
    public:
        int maxAreaOfIsland(vector<vector<int>>& grid) {
            int res=0;
            for(int i=0;i<grid.size();i++){
                for(int j=0;j<grid[0].size();j++){
                    if(grid[i][j]==1){
                        res=max(res,helper(grid,i,j,0));
                    }
                }
            }
            return res;
        }
        int helper(vector<vector<int>>& grid,int row,int col,int sum){
            if(row<0||row>=grid.size()||col<0||col>=grid[0].size()||grid[row][col]!=1){
                return 0;
            }
            grid[row][col]=0;
            sum++;
            sum+=helper(grid,row-1,col,0)
            +helper(grid,row+1,col,0)
            +helper(grid,row,col-1,0)
            +helper(grid,row,col+1,0);
            return sum;
        }
    };
    复制代码

    从这个题中,可以利用递归,把一个树的所有叶子节点按从左到右的顺序放入vector<int>型中。

    复制代码
    class Solution {
    public:
        bool leafSimilar(TreeNode* root1, TreeNode* root2) {
            vector<int> res1,res2;
            vert(root1,res1);
            vert(root2,res2);
            if(res1==res2) return true;
            return false;
        }
        void vert(TreeNode* root,vector<int>& res){
            //递归终止条件
            if(!root) return;
            //本层要做的事:先找到左边的叶子节点,把val放入res中,再对右叶子做同样操作
            vert(root->left,res);
            //判断叶子节点的条件
            if(!root->left&&!root->right) res.push_back(root->val);
            vert(root->right,res);
        }
    };
    复制代码

     从这个题中学到了用map,实现映射,其实也算hash。以便某些题目需要的时候避免了反复用循环来查询。但map需要初始化。

    map 的实现是红黑树,unordered_map的实现是hash。

     借鉴评论(此代码超时)用stack存储:

    这其实也是广度优先搜索,但是效率没有下面的高。

    复制代码
    class Solution {
    public:
        int getImportance(vector<Employee*> employees, int id) {
            stack<int> e;
            int count=0;
            e.push(id);
            while(!e.empty()){
                int node=e.top();
                vector<int> vec;
                e.pop();
                for(int i=0;i<employees.size();i++){
                    if(employees[i]->id==id){
                        count += employees[i]->importance;
                        vec=employees[i]->subordinates;
                        for(int j=0;j<vec.size();j++){
                            e.push(vec[j]);
                        }
                        break;
                    }
                }
            }
            return count;
        }
    };
    复制代码

     

    用map 存储

    深搜(递归):

    复制代码
    class Solution {
    public:
        int getImportance(vector<Employee*> employees, int id) {
            map<int,Employee*> m;
            for(auto e:employees){//初始化map
                m[e->id]=e;
            }
            int res=dfs(id,m);
            return res;
        }
        int dfs(int id,map<int,Employee*> map){
            if(map[id]->subordinates.size()==0) return map[id]->importance;
            int imp=map[id]->importance;
            for(auto tmp:map[id]->subordinates){
                imp += dfs(tmp,map);
            }
            return imp;
        }
    };
    复制代码

     来自巨佬的代码:

    广度优先搜索:

    先介绍unordered_map:

    https://www.cnblogs.com/tp-16b/p/9156810.html

    复制代码
    class Solution {
    public:
        int getImportance(vector<Employee*> employees, int id) {
            int sumImportance=0;
            unordered_map<int,Employee*> hashMap;
            //初始化
            for(auto employee:employees){
                hashMap[employee->id]=employee;
            }
            queue<int> myQue;//广度优先搜索队列
            myQue.push(id);
            //开始搜索
            while(!myQue.empty()){
                id=myQue.front();
                myQue.pop();
                sumImportance += hashMap[id]->importance;
                for(auto subordinate:hashMap[id]->subordinates){
                    myQue.push(subordinate);
                }   
            }
            return sumImportance;
        }
    };
    复制代码

                    

     思路:利用中序遍历得到vector,之后就好办了!

    复制代码
    class Solution {
    public:
        TreeNode* increasingBST(TreeNode* root) {
            if(!root) return NULL;
            vector<int> v=inorderTraversal(root);
            TreeNode* temp=new TreeNode(v[0]);
            TreeNode* p=temp;
            temp->left=NULL;
            for(int i=1;i<=v.size()-1;i++){
                TreeNode* node=new TreeNode(v[i]);
                temp->right=node;
                temp=node;
            }
            return p; 
        }
        //中序遍历
        vector<int> inorderTraversal(TreeNode* root) {
            stack<TreeNode*> stk;
            vector<int> vec;
            while(root!=NULL||!stk.empty()){
                if(root!=NULL){//根节点进栈,遍历左子树
                    stk.push(root);
                    root=root->left;
                }
                else{//根节点退栈,访问根节点,遍历右子树
                    root=stk.top(); stk.pop();
                    vec.push_back(root->val);
                    root=root->right;
                }
            }
            return vec;
            
        }
    };
    复制代码

     解法1:

    思路:借鉴评论区的代码。深搜。但是效率不高。自己没想起来怎么写。

    复制代码
    class Solution {
        vector<vector<int>> res;//要在这里声明全局变量
        vector<int> result;
    public: 
        vector<vector<int>> pathSum(TreeNode* root, int sum) {
            
            path(root,sum,result);
            return res;
            
        }
        void path(TreeNode* root,int sum,vector<int> p){ //注意这里没加引用。可能是因为全局变量
            if(!root){//递归终止条件
                return;
            }
            p.push_back(root->val);
            if(!(root->left)&&!(root->right)&&sum==root->val)//一直往下找,直到找到路径总和为sum的元素
                res.push_back(p);
            path(root->left,sum - root->val,p);
            path(root->right,sum - root->val,p);
        }
        
    };
    复制代码

    解法2:

    思路:比上一个解法多了一个回溯。效率增加了很多。代码借鉴的题解

    复制代码
    class Solution {
    
    public: 
        vector<vector<int>> pathSum(TreeNode* root, int sum) {
            vector<vector<int>> res;//要在这里声明全局变量
            vector<int> result;
            path(root,sum,res,result);
            return res;
            
        }
        void path(TreeNode* root,int sum,vector<vector<int>> &res,vector<int> &result){ //注意这里加了引用。可能是局部变量,所以要加引用
            if(!root){//递归终止条件
                return;
            }
            sum=sum-root->val;
            result.push_back(root->val);
            if(sum==0&&root->left==NULL&&root->right==NULL){
                res.push_back(result);
            }
            if(root->left){
                path(root->left,sum,res,result);
                result.pop_back();//回溯
            }
            if(root->right){
                path(root->right,sum,res,result);
                result.pop_back();//回溯
            }
                
        }
        
    };
    复制代码

    回溯和递归的区别:(非常重要!):总的来说,回溯算法和递归算法不能以类别的形式进行比较。在很多情况下,二者是一起使用的。 

    区别与联系

    • 递归是一种算法结构。
    • 回溯是一种算法思想,可以用递归实现。

    https://blog.csdn.net/lym940928/article/details/89679157


     

    解法1:递归就完事了

    复制代码
    class Solution {
    public:
        int sumNumbers(TreeNode* root) {
            return helper(root,0);
        }
        int helper(TreeNode* root,int sum){
            if(!root){
                return 0;
            }
            else if(!root->left&&!root->right){
                return 10*sum+root->val;
            }
            return helper(root->left,10*sum+root->val)+helper(root->right,10*sum+root->val);
        }
    };
    复制代码

     

    解法1:

    思路:(借鉴评论)双栈。一个栈存储奇数行的结点。一个栈存储偶数行的结点

    复制代码
    class Solution {
    public:
        vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
            vector<vector<int>> res;
            if(!root)
                return res;
            stack<TreeNode*> sta1;//遍历中使用的临时栈1,存放奇数层节点
            stack<TreeNode*> sta2;//遍历中使用的临时栈2,存放偶数层节点
            sta2.push(root);
            int index=0;//用于保存当前的层数
            while(sta1.size()||sta2.size()){
                vector<int> tempres;//本层遍历的结果
                if(index%2==0){
                    while(sta2.size()){
                        //从栈2中出栈
                        TreeNode* temp=sta2.top();
                        sta2.pop();
                        //输出结点
                        tempres.push_back(temp->val);
                        //将子节点入栈1,偶数行先左后右
                        if(temp->left)
                            sta1.push(temp->left);
                        if(temp->right)
                            sta1.push(temp->right);
                    }
                }
                else{
                    while(sta1.size()){
                        //从栈1中出栈
                        TreeNode* temp=sta1.top();
                        sta1.pop();
                        //输出结点
                        tempres.push_back(temp->val);
                        //将子节点入栈2,奇数行先右后左
                        if(temp->right)
                            sta2.push(temp->right);
                        if(temp->left)
                            sta2.push(temp->left);
                    }
                }
                //将本层的结点输出加入结果中,更新层数
                index += 1;
                res.push_back(tempres);
            }
            return res;
        }
    };
    复制代码

    解法2:

    思路:(评论区) 双端队列


     

    解法1:

    思路:利用BFS,队列,判断是否为同一层和同一父节点。若是同一层且父节点不同,则说明为堂兄弟

    复制代码
    class Solution {
    public:
        bool isCousins(TreeNode* root, int x, int y) {//判断是否为同一父节点和同一层
            if(x==y)//当两个结点为指向同一个结点时
                return true;
            queue<TreeNode*> record;
            record.push(root);
            int count=1;
            while(!record.empty()){
                int flag_x=0,flag_y=0;
                while(count--){//每层的元素个数
                    TreeNode* temp=record.front();
                    record.pop();
                    if(temp->left&&temp->right&&((temp->left->val==x&&temp->right->val==y)||(temp->left->val==y&&temp->right->val==x)))
                        return false;
                    if(temp->val==x)
                       flag_x=1;
                    if(temp->val==y)
                        flag_y=1;
                    if(flag_x&&flag_y)
                        return true;
                    if(temp->left)
                        record.push(temp->left);
                    if(temp->right)
                        record.push(temp->right);
                
                }
                count=record.size();
            }
            return false;
        }
    };
    复制代码

     

    解法1:思路:大佬的DFS。

    利用了C++中的resize()函数

     

    复制代码
    class Solution {
    public:
        vector<int> largestValues(TreeNode* root) {
            dfs(root,0);
            return res;
        }
        void dfs(TreeNode* root,int depth){
            if(!root){
                return;
            }
            if(depth>=res.size()){
                res.resize(depth+1,INT_MIN);
            }
            res[depth] = max(res[depth],root->val);
            dfs(root->left,depth+1);
            dfs(root->right,depth+1);
            
        }
        private:
        vector<int> res;
    };
    复制代码

     解法2:

    BFS广度搜索

    复制代码
    class Solution {
    public:
        vector<int> largestValues(TreeNode* root) {
            vector<int> res;
            queue<TreeNode*> q;
            if(!root) return res;
            q.push(root);
            while(!q.empty()){
                int sz = q.size();
                int max = INT_MIN;
                for(int i=0; i<sz; ++i){
                    TreeNode* t = q.front();
                    q.pop();
                    if(t->val > max) max = t->val;
                    if(t->left) q.push(t->left);
                    if(t->right) q.push(t->right);
                }
                res.push_back(max);
            }
            return res;
        }
    };
    复制代码

     

     解法1:

    思路:把树转为图,就成了距离该节点为K的节点了。

    复制代码
    class Solution {
    public:
        vector<int> distanceK(TreeNode* root, TreeNode* target, int K) {
            vector<int> res;
            map<TreeNode*, vector<TreeNode*>> conn;
            dfs(root,conn);//建立邻接矩阵
            queue<TreeNode*> q;
            set<TreeNode*> visited;
            q.push(target);
            visited.insert(target);
            int step = 0;
            while(!q.empty()){
                if(step == K){
                    while(!q.empty()){
                        res.push_back(q.front()->val);
                        q.pop();
                    }
                    return res;//一定在这里返回
                }
                int size = q.size();
                for(int i=0; i<size;i++){
                    TreeNode* curr = q.front();
                    q.pop();
                    for(int j =0;j<conn[curr].size();j++){
                        TreeNode* next = conn[curr][j];
                        if(visited.find(next)!= visited.end()) continue;//如果被访问过,则继续循环
                        visited.insert(next);
                        q.push(next);
                    }
                }
                step++;
            }
            return res;//不会在这里返回
        }
        void dfs(TreeNode* root, map<TreeNode*,vector<TreeNode*>>& conn){//DFS建立邻接矩阵
            if(!root) return;
            if(root->left){
                conn[root].push_back(root->left);
                conn[root->left].push_back(root);
                dfs(root->left,conn);
            }
            if(root->right){
                conn[root].push_back(root->right);
                conn[root->right].push_back(root);
                dfs(root->right,conn);
            }
        }
    };
    复制代码

     

    广搜,入队列

     解法1:思路:使用层序遍历,并只保留每层最后一个节点的值

    复制代码
    class Solution {
    public:
        vector<int> rightSideView(TreeNode* root) {
            vector<int> res;
            if(!root) return res;
            queue<TreeNode*> q;
            q.push(root);
            while(!q.empty()){
                int size = q.size();
                res.push_back(q.front()->val);
                while(size--){
                    TreeNode* temp = q.front();
                    q.pop();
                    if(temp->right) q.push(temp->right);//一定要最右节点先入队
                    if(temp->left) q.push(temp->left);
                }
            }
            return res;
        }
    };
    复制代码

     

    先贴上代码,慢慢看。

    自己在深搜广搜,图的应用还是不熟练。

    复制代码
    class Solution {
    public:
        int minKnightMoves(int x, int y) {
            if ( x==0 && y==0 ) return 0;
            
            x += 300;
            y += 300;
            int dir[8][2] = { {1,2},{2,1},{1,-2},{2,-1},{-1,2},{-2,1},{-1,-2},{-2,-1} };
            int level = 0;
            queue<pair<int,int>> q;
            q.push({300,300});
            int vis[1000][1000]={0};
            vis[300][300] = 1 ;
            while( !q.empty() ){
                for ( int t=q.size()-1; t>=0; --t ){
                    pair<int,int> cor = q.front(); q.pop();
                    for ( int k=0; k<8; ++k ){
                        int ny = cor.first + dir[k][0];
                        int nx = cor.second + dir[k][1];
                        if ( ny==y && nx==x ) return level +1 ;
                        if ( nx>=0 && ny>=0 && nx<=603 && ny<=603 && vis[ny][nx]==0 ){
                            q.push({ny,nx});
                            vis[ny][nx]=1;
                        }
                    }
                }
                ++level;
            }
            return -1;
        }
    };
    复制代码

    参考题解:

    https://leetcode.com/problems/word-ladder/discuss/40707/C%2B%2B-BFS

    注意:判断有一个字母不同,其他字母都相同的代码是如何写的。

    解法1:

    2019-10-09(第一次)

    BFS

    注意:判断有一个字母不同,其他字母都相同的代码是如何写的。

    复制代码
    class Solution {
    public:
        int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
            unordered_set<string> dict(wordList.begin(),wordList.end());
            int Lader = 1;
            queue<string> q;
            q.push(beginWord);
            while(!q.empty()){
                int n = q.size();
                for(int i=0;i<n;++i){
                    string word = q.front();
                    q.pop();
                    if(word == endWord){
                        return Lader;
                    }
                    dict.erase(word);
                    for(int j=0;j<word.size();++j){
                        char c= word[j];
                        for(int k=0;k<26;++k){//判断有一个字母不同,其他字母都相同的代码是如何写的
                            word[j] = 'a' + k;
                            if(dict.find(word)!=dict.end()){
                                q.push(word);
                            }
                        }
                        word[j] = c;
                    }
                }
                Lader++;
            }
            return 0;
        }
    };
    复制代码

  • 相关阅读:
    【LCA倍增】POJ1330-Nearest Common Ancestors
    【AC自动机/fail树】BZOJ3172- [Tjoi2013]单词
    【费用流】BZOJ1221-[HNOI2001] 软件开发
    【KM】POJ2195/HDU1533-Going home
    【KM算法】HDU2255-奔小康赚大钱
    【匈牙利算法】BZOJ1059-[ZJOI2007]矩阵游戏
    【KMP】BZOJ3670-[Noi2014]动物园
    【Treap】BZOJ1588-[HNOI2002]营业额统计
    【Treap模板详细注释】BZOJ3224-普通平衡树
    【tarjan求割顶】BZOJ2730-[HNOI2012]矿场搭建
  • 原文地址:https://www.cnblogs.com/JasonPeng1/p/12116592.html
Copyright © 2011-2022 走看看