五月集训(第15天)—深度优先搜索(DFS)

深度优先搜索(Depth First Search, DFS)

1. 565. 数组嵌套

    思路:
        一开始以每个点为起点暴力深搜,结果超时了。发现染色法是真不错,每次深搜染成不一样的颜色,这样染过色的点就不用再当成起点了,因为它必然是之前答案的后缀,集合元素不是最大的。而且利用染色法深搜只需要将hash初始化一次即可。

class Solution {
    int hash[200010];
    int cnt = 0;
public:
    void dfs(int index, vector<int> &nums, int color) {
        if (hash[index] != -1) return ;
        hash[index] = color;
        cnt++;
        dfs(nums[index], nums, color);
    }

    int arrayNesting(vector<int>& nums) {
        int color = 0, maxn = 0;
        int n = nums.size();
        memset(hash, -1, sizeof(hash));
        for (int i = 0; i < n; i++) {
            if (hash[i] == -1) {
                cnt = 0;
                dfs(nums[i], nums, color++);
                maxn = max(maxn, cnt);
            }
        }
        return maxn;
    }
};

2. 401. 二进制手表

    思路:
        把表示时间的LED和表示分钟的LED放一起看,认为有10个LED,求从中取出turnedOn个的全排列,按照全排列的对应LED求出表示的时间即可。

class Solution {
    int hours[10] =   {1, 2, 4, 8, 0, 0, 0, 0, 0, 0};
    int minutes[10] = {0, 0, 0, 0, 1, 2, 4, 8, 16, 32};
    bool vis[11];
public:
    void dfs(vector<string> &ret, int turnedOn, int hour, int minute, int index) {
        if (hour > 11 || minute > 59) return ;
        if (turnedOn == 0) {
            string ans;
            ans = to_string(hour) + ":" + (minute < 10 ? ("0" + to_string(minute)) : to_string(minute));
            ret.push_back(ans);
            return ;
        }

        for (int i = index; i < 10; i++) {
            if (!vis[i]) {
                vis[i] = true;
                dfs(ret, turnedOn - 1, hour + hours[i], minute + minutes[i], i);
                vis[i] = false;
            }
        }
    }

    vector<string> readBinaryWatch(int turnedOn) {
        vector<string> ret;
        memset(vis, 0, sizeof(vis));
        dfs(ret, turnedOn, 0, 0, 0);
        return ret;
    }
};

3. 1079. 活字印刷

在这里插入图片描述

    思路:
        求字母的组合

  • 首先将字母与数字1~7建立映射关系。
  • 求出数字排列的所有可能(包括各种前缀)。
  • 将当前的排列与一个整数建立映射关系,利用hash判断当前排列是否出现过,未出现过则结果cnt++

class Solution {
    int vis[7777777+10]; // 7的全排列转化为整数表示
    bool vis_map[10];
    int cnt = 0;
public:
    void dfs(int mmap[], int index, int len, int ans) {
        if (index != 0) cnt++;
        for (int i = 1; i <= len; i++) {
            if (!vis_map[i]) {
                vis_map[i] = 1;
                if (-1 == vis[ ans * 10 + mmap[i] ]) {
                    vis[ ans * 10 + mmap[i] ] = 1;
                    dfs(mmap, i, len, ans * 10 + mmap[i]);
                }
                vis_map[i] = 0;
            }
        }
    }

    int numTilePossibilities(string tiles) {
        int len = tiles.length();

        // 将tiles压缩为0~6之间的数字,方便作全排列
        int order = 0;
        int nums[27], mmap[10];
        memset(nums, -1, sizeof(nums));
        for (int i = 0; i < len; i++) {
            if (-1 == nums[tiles[i] - 'A']) {
                nums[tiles[i] - 'A'] = ++order;
            }
            mmap[i + 1] = nums[tiles[i] - 'A'];
        }

        // 求全排列
        memset(vis, -1, sizeof(vis));
        memset(vis_map, 0, sizeof(vis_map));
        dfs(mmap, 0, len, 0);
        return cnt;
    }
};

4. 1219. 黄金矿工

    思路:
        每次选取一个新的起点,从起点出发向四周寻找非零的矿,找到则财富累积,找不到且无路可走时返回。利用深度优先搜索 + 回溯实现。

class Solution {
    bool vis[16][16];
    int dir[4][2] = {{0, -1}, {1, 0}, {0, 1}, {-1, 0}};
    int maxn = 0;
    int n, m;
public:
    int check(int x, int y) {
        if (x < 0 || x >= n || y < 0 || y >= m) return 0;
        if (vis[x][y]) return 0;
        return 1;
    }

    void dfs(vector<vector<int>> &grid, int cnt, int last_x, int last_y) {
        maxn = max(maxn, cnt);
        int x, y;
        for (int i = 0; i < 4; i++) {
            x = last_x + dir[i][0];
            y = last_y + dir[i][1];
            if (check(x, y) && grid[x][y] > 0) {
                vis[x][y] = 1;
                dfs(grid, cnt + grid[x][y], x, y);
                vis[x][y] = 0;
            }
        }
    }

    int getMaximumGold(vector<vector<int>>& grid) {
        n = grid.size();
        m =grid[0].size();
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] > 0) {
                    vis[i][j] = 1;
                    dfs(grid, grid[i][j], i, j);
                    vis[i][j] = 0;
                }
            }
        }
        return maxn;
    }
};
posted @ 2022-05-15 10:47  番茄元  阅读(31)  评论(0)    收藏  举报