五月集训(第十五日)深度优先搜索

一、565. 数组嵌套

1.原题链接

565. 数组嵌套

2.题目描述

        索引从0开始长度为N的数组A,包含0到N - 1的所有整数。找到最大的集合S并返回其大小,其中 S[i] = {A[i], A[A[i]], A[A[A[i]]], … }且遵守以下的规则。假设选择索引为i的元素A[i]为S的第一个元素,S的下一个元素应该是A[A[i]],之后是A[A[A[i]]]… 以此类推,不断添加直到S出现重复的元素。

3.解题思路

        深度优先搜索

4.源码

class Solution {
public:
    int arrayNesting(vector<int>& nums) {
        int n = nums.size();
        vector<bool> used(n,false);
        int res = 0;
        for(int i = 0;i<n;i++){
            if(!used[i]){
                res = max(res,dfs(nums,used,i,n));
            }
        }
        return res;
    }

    int dfs(vector<int>& nums,vector<bool>& used,int &i,int &n){
        if(i>=n){
            return 0;
        }
        if(used[i]){
            return 0;
        }
        used[i] = true;
        return 1 + dfs(nums,used,nums[i],n);
    }
};

二、401. 二进制手表

1.原题链接

401. 二进制手表

2.题目描述

        二进制手表顶部有 4 个 LED 代表 小时(0-11),底部的 6 个 LED 代表 分钟(0-59)。每个 LED 代表一个 0 或 1,最低位在右侧。

3.解题思路

        枚举所有 2^10=1024 种灯的开闭组合,即用一个二进制数表示灯的开闭,其高 4位为小时,低 6 位为分钟。若小时和分钟的值均在合法范围内,且二进制中 1 的个数为 turnedOn,则将其加入到答案中。

4.源码

class Solution {
public:
    vector<string> readBinaryWatch(int turnedOn) {
        vector<string> ans;
        for (int i = 0; i < 1024; ++i) {
            int h = i >> 6, m = i & 63; // 用位运算取出高 4 位和低 6 位
            if (h < 12 && m < 60 && __builtin_popcount(i) == turnedOn) {
                ans.push_back(to_string(h) + ":" + (m < 10 ? "0" : "") + to_string(m));
            }
        }
        return ans;
    }
};

三、1079. 活字印刷

1.原题链接

1079. 活字印刷

2.题目描述

        你有一套活字字模 tiles,其中每个字模上都刻有一个字母 tiles[i]。返回你可以印出的非空字母序列的数目。注意:本题中,每个活字字模只能使用一次。

3.解题思路

        哈希数组加回溯

4.源码

class Solution {
public:
    int res;

    void dfs(map<char, int>& hash) {
        for (auto& data : hash) {
            if (data.second > 0) {
                data.second--;
                res++;
                dfs(hash);
                data.second++;
            }
        }
    }

    int numTilePossibilities(string tiles) {
        map<char, int> hash;
        for (int i = 0; i < tiles.size(); i++) {
            hash[tiles[i]]++;
        }
        dfs(hash);
        return res;
    }
};

四、1219. 黄金矿工

1.原题链接

1219. 黄金矿工

2.题目描述

        你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量;如果该单元格是空的,那么就是 0。为了使收益最大化,矿工需要按以下规则来开采黄金:每当矿工进入一个单元,就会收集该单元格中的所有黄金。矿工每次可以从当前位置向上下左右四个方向走。每个单元格只能被开采(进入)一次。不得开采(进入)黄金数目为 0 的单元格。矿工可以从网格中 任意一个 有黄金的单元格出发或者是停止。

3.解题思路

        深度优先记忆化搜索

4.源码

class Solution {
public:
    int maxv = 0, tsum = 0;
    int dx[4] = {0, 0, 1, -1};
    int dy[4] = {1, -1, 0, 0};
    
    void dfs(int tx, int ty, vector<vector<int>>& grid) {
        if (tx < 0 || ty < 0 || tx >= grid.size() || ty >= grid[0].size() || grid[tx][ty] == 0) return ;
        int temp = grid[tx][ty];
        tsum += temp;
        maxv = max(maxv, tsum);
        grid[tx][ty] = 0;
        for (int i=0; i<4; i++) {
            int px = tx + dx[i];
            int py = ty + dy[i];
            dfs(px, py, grid);
        }
        grid[tx][ty] = temp;
        tsum -= temp;
    }
    
    int getMaximumGold(vector<vector<int>>& grid) {
        for (int i=0; i<grid.size(); i++) 
            for (int j=0; j<grid[i].size(); j++) 
                if (grid[i][j] != 0)
                    dfs(i, j, grid);
        return maxv;
    }
};

总结

        第十五天,任务过半,还需加油。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

枏念

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值