【LeetCode - 每日一题】1079. 活字印刷(2023.05.19)

1079. 活字印刷

题意

  • 字模无序。
  • 每个字模仅能使用 1 次。
  • 返回所有的非空子集的数量。

解法1 dfs + set

因为 tiles 的长度很小,所以可以遍历其长度,从而将题目转换成若干个 全排列 问题。

对于得到的重复的排列,使用 set 自动去重。

同层剪枝:
因为字模可能有重复,所以在 dfs 时会出现大量的重复序列,而这些重复序列的出现本质上是在 s[i] 位置上放了重复的字符。因此,

  • 首先对 tiles 进行排序,使得重复的字符排列在一块儿
  • 然后在 dfs 过程中,判断 if(vis[i]||(i>0&&new_tiles[i]==new_tiles[i-1]&&!vis[i-1])) continue;。对于重复的字符 a1a2a3,当 a1 被放在 s[i] 后,该层的 dfs 会回溯到上一步,此时 vis(a1) 被重置为 0 ,因此,当遍历到 a2 时,满足 i>0&&new_tiles[i]==new_tiles[i-1]&&!vis[i-1],因此直接跳过。
class Solution {
public:
    unordered_set<string> st;
    void dfs(string tiles, string s, vector<int> vis, int len)
    {
        if(s.size()==len)
        {
            st.insert(s);
            return;
        }
        for(int i=0;i<tiles.size();i++)
        {
            if(!vis[i])
            {
                s=s+tiles[i];
                vis[i]=1;
                dfs(tiles, s, vis, len);
                s=s.substr(0,s.size()-1);
                vis[i]=0;
            }
        }
    }
    int numTilePossibilities(string tiles) {
        int n=tiles.size();
        for(int i=1;i<=n;i++)
        {
            string s="";
            vector<int> vis(n,0);
            dfs(tiles, s, vis, i);
        }
        return st.size();
    }
};


// 同层剪枝
class Solution {
public:
    unordered_set<string> st;
    void dfs(vector<char> new_tiles, string s, vector<int> vis, int len)
    {
        if(s.size()==len)
        {
            st.insert(s);
            return;
        }
        for(int i=0;i<new_tiles.size();i++)
        {
            if(vis[i]||(i>0&&new_tiles[i]==new_tiles[i-1]&&!vis[i-1])) continue;

            s=s+new_tiles[i];
            vis[i]=1;
            dfs(new_tiles, s, vis, len);
            s=s.substr(0,s.size()-1);
            vis[i]=0;
        }
    }
    int numTilePossibilities(string tiles) {
        int n=tiles.size();

        vector<char> new_tiles;
        for(int i=0;i<tiles.size();i++)
            new_tiles.push_back(tiles[i]);

        sort(new_tiles.begin(),new_tiles.end());
        
        for(int i=1;i<=n;i++)
        {
            string s="";
            vector<int> vis(n,0);
            dfs(new_tiles, s, vis, i);
        }
        return st.size();
    }
};

46. 全排列

题意

  • 板子题

解法 dfs

全排列的实质是创建了一棵树,每一层对应了全排列的每个位置,对于位置 idx,首先插入一个未插入过的元素,然后 dfs 到底,然后回溯到位置 idx,再次插入一个未插入过的元素,所以,记得回溯时的更新!!!

class Solution {
public:
    vector<vector<int>> anss;
    void dfs(vector<int> num, vector<int> ans, vector<int> vis)
    {
        if(ans.size()==num.size()) 	//一次全排列结束,保存该次全排列
        {
            anss.push_back(ans);
            return ;
        }
        for(int i=0;i<num.size();i++) 	//遍历所有元素
        {
            if(vis[i]!=1)
            {
            	// 插入一个新元素
                vis[i]=1;
                ans.push_back(num[i]); 	
                dfs(num, ans,vis);
				
				// 回溯插入的元素,从而在同一个位置插入其他元素(一定要回溯!)
                ans.pop_back();
                vis[i]=0;
            }
        }
    }
    vector<vector<int>> permute(vector<int>& nums) {
        vector<int> ans; 	//记录每次排列
        vector<int> vis(nums.size(),0); 	//记录每个元素是否被排列
        dfs(nums,ans,vis);
        return anss;
    }
};

47. 全排列 II

题意

  • 带重复元素的全排列

解法 dfs

因为元素可能有重复,所以在 dfs 时会出现大量的重复序列,而这些重复序列的出现本质上是在 s[i] 位置上放了重复的字符。因此,

  • 首先对 nums 进行排序,使得重复的字符排列在一块儿
  • 然后在 dfs 过程中,判断 if(vis[i]||(i>0&&nums[i]==nums[i-1]&&!vis[i-1])) continue;。对于重复的字符 a1a2a3,当 a1 被放在 s[i] 后,该层的 dfs 会回溯到上一步,此时 vis(a1) 被重置为 0 ,因此,当遍历到 a2 时,满足 i>0&&nums[i]==nums[i-1]&&!vis[i-1],因此直接跳过。
class Solution {
public:
    vector<vector<int>> anss;
    void dfs(vector<int> nums, vector<int> ans, vector<int> vis)
    {
        if(ans.size()==nums.size())
        {
            anss.push_back(ans);
            return ;
        }
        for(int i=0;i<nums.size();i++)
        {
            // 被用过, 之前的重复数字被用过,跳过
            if(vis[i]||(i>0&&nums[i]==nums[i-1]&&!vis[i-1]))
            {
                continue;
            }
            ans.push_back(nums[i]);
            vis[i]=1;
            dfs(nums,ans,vis);
            vis[i]=0;
            ans.pop_back();
        }
    }
    vector<vector<int>> permuteUnique(vector<int>& nums) {
        sort(nums.begin(),nums.end());  //从小大 排序
        vector<int> ans;
        vector<int> vis(nums.size(),0);
        dfs(nums,ans,vis);
        return anss;
    }
};

你可能感兴趣的:(leetcode,c++,leetcode,算法)