【力扣】从零开始的 dfs(全排列,回溯)

从零开始的 dfs(全排列,回溯)

46. 全排列

46. 全排列

给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。

class Solution {
    static int n;
    static boolean[] visit;
    static List<List<Integer>> res;
    public List<List<Integer>> permute(int[] nums) {
        n=nums.length;
        res=new ArrayList<>();
        Deque<Integer> deque=new ArrayDeque<>();
        visit=new boolean[n];
        dfs(deque,0,nums);
        return res;
    }
    static void dfs(Deque<Integer> deque,int len,int[] nums)
    {
        if(len==n)
        {
            res.add(new ArrayList<>(deque));
            return;
        }
        for(int i=0;i<n;i++)
        {
            if(visit[i]==false)
            {
                visit[i]=true;
                deque.addLast(nums[i]);
                dfs(deque,len+1,nums);
                visit[i]=false;
                deque.removeLast();
            }
        }
        return ;
    }
}

47. 全排列 II

47. 全排列 II

给定一个可包含重复数字的序列 nums按任意顺序 返回所有不重复的全排列。

示例 1:

输入:nums = [1,1,2]
输出:
[[1,1,2],
 [1,2,1],
 [2,1,1]]

解题思路

​ 这题和上一题要求去重,要解决重复问题,我们只要设定一个规则,保证在填第 i 个数的时候重复数字只会被填入一次即可。而在本题解中,我们选择对原数组排序,保证相同的数字都相邻,然后每次填入的数一定是这个数所在重复数集合中「从左往右第一个未被填过的数字」,即如下的判断条件:

if(i>0 && nums[i]==nums[i-1] && visit[i-1]==false)
	continue;
class Solution {
    static int n;
    static boolean[] visit;
    static List<List<Integer>> res;
    public List<List<Integer>> permuteUnique(int[] nums) {
        n=nums.length;
        res=new ArrayList<>();
        Deque<Integer> deque=new ArrayDeque<>();
        visit=new boolean[n];
        Arrays.sort(nums);
        dfs(deque,0,nums);

        return res;
    }
    static void dfs(Deque<Integer> deque,int len,int[] nums)
    {
        if(len==n)
        {
            res.add(new ArrayList<>(deque));
            return;
        }
        for(int i=0;i<n;i++)
        {
            if(i>0 && nums[i]==nums[i-1] && visit[i-1]==false)
                continue;
            if(visit[i]==false)
            {
                visit[i]=true;
                deque.addLast(nums[i]);
                dfs(deque,len+1,nums);
                visit[i]=false;
                deque.removeLast();
            }
        }
        return ;
    }
}

77. 组合

77. 组合

给定两个整数 nk,返回范围 [1, n] 中所有可能的 k 个数的组合。

你可以按 任何顺序 返回答案。

示例 1:

输入:n = 4, k = 2
输出:
[
  [2,4],
  [3,4],
  [2,3],
  [1,2],
  [1,3],
  [1,4],
]
class Solution {
    static List<List<Integer>> res;//答案
    static boolean[] visit;//标记
    public List<List<Integer>> combine(int n, int k) {
        res=new ArrayList<>();
        visit=new boolean[n+1];//[1,n]
        Deque<Integer> deque=new ArrayDeque<>();
        dfs(deque,0,k,n,1);
        return res;
    }
    static void dfs(Deque<Integer> deque,int s,int k,int n,int c)
    {
        if(s==k)
        {
            res.add(new ArrayList<>(deque));
            return;
        }
        for(int i=c;i<=n;i++)
        {

            if(visit[i]==false)
            {
                visit[i]=true;
                deque.addLast(i);
                dfs(deque,s+1,k,n,i+1);
                deque.removeLast();
                visit[i]=false;
            }
        }
        return;
    }
}

78. 子集

78. 子集

给你一个整数数组 nums ,数组中的元素 互不相同 。返回该数组所有可能的子集(幂集)。

解集 不能 包含重复的子集。你可以按 任意顺序 返回解集。

示例 1:

输入:nums = [1,2,3]
输出:[[],[1],[2],[1,2],[3],[1,3],[2,3],[1,2,3]]
class Solution {
    static boolean[] visit;//标记数组
    static List<List<Integer>> res;//结果
    static int n;//测试样例长度
    public List<List<Integer>> subsets(int[] nums) {
        Deque<Integer> deque=new ArrayDeque<>();
        res=new ArrayList<>();
        n=nums.length;
        visit=new boolean[n];
        //遍历长度从0到n-1
        for(int i=0;i<=n;i++)
        {
            Arrays.fill(visit,false);
            dfs(deque,0,i,nums,0);
        }
        return res;
    }
    static void dfs(Deque<Integer> deque,int s,int k,int[] nums,int c)
    {
        if(s==k)
        {
            res.add(new ArrayList<>(deque));
            return;
        }
        for(int i=c;i<n;i++)
        {
            if(visit[i]==false)
            {
                visit[i]=true;
                deque.addLast(Integer.valueOf(nums[i]));
                dfs(deque,s+1,k,nums,i+1);
                deque.removeLast();
                visit[i]=false;
            }
        }
        return;
    }
}

79. 单词搜索

79. 单词搜索

给定一个 m x n 二维字符网格 board 和一个字符串单词 word 。如果 word 存在于网格中,返回 true ;否则,返回 false

单词必须按照字母顺序,通过相邻的单元格内的字母构成,其中“相邻”单元格是那些水平相邻或垂直相邻的单元格。同一个单元格内的字母不允许被重复使用。

示例 1:

img

输入:board = [["A","B","C","E"],["S","F","C","S"],["A","D","E","E"]], word = "ABCCED"
输出:true
class Solution {
    static int n,m,l;//方格大小
    static boolean f;//答案
    static int[] dx=new int[]{0,0,1,-1};
    static int[] dy=new int[]{1,-1,0,0};//方向数组
    static boolean[][] visit;//标记数组
    public boolean exist(char[][] board, String word) {
        n=board.length;
        m=board[0].length;
        l=word.length();
        f=false;
        visit=new boolean[n][m];
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                for(boolean[] b:visit)
                {
                    Arrays.fill(b,false);
                }
                if(board[i][j]==word.charAt(0))
                {
                    visit[i][j]=true;
                    dfs(board,0,i,j,word);
                    if(f==true)
                    {
                        return true;
                    }
                }
            }
        }
        return false;
    }
    static void dfs(char[][] board,int s,int i,int j,String word)
    {
        if(s==l-1)
        {
            f=true;
            return;
        }
        for(int q=0;q<4;q++)
        {
            int x=dx[q]+i;
            int y=dy[q]+j;
            if (x>=0 && x<n && y>=0 && y<m && visit[x][y]==false && board[x][y] == word.charAt(s + 1)) {
                visit[x][y]=true;
                dfs(board, s + 1, x, y, word);
                visit[x][y]=false;
            }
        }
        return;

    }
}

1219. 黄金矿工

1219. 黄金矿工

你要开发一座金矿,地质勘测学家已经探明了这座金矿中的资源分布,并用大小为 m * n 的网格 grid 进行了标注。每个单元格中的整数就表示这一单元格中的黄金数量;如果该单元格是空的,那么就是 0

为了使收益最大化,矿工需要按以下规则来开采黄金:

  • 每当矿工进入一个单元,就会收集该单元格中的所有黄金。
  • 矿工每次可以从当前位置向上下左右四个方向走。
  • 每个单元格只能被开采(进入)一次。
  • 不得开采(进入)黄金数目为 0 的单元格。
  • 矿工可以从网格中 任意一个 有黄金的单元格出发或者是停止。

示例 1:

输入:grid = [[0,6,0],[5,8,7],[0,9,0]]
输出:24
解释:
[[0,6,0],
 [5,8,7],
 [0,9,0]]
一种收集最多黄金的路线是:9 -> 8 -> 7
class Solution {
    static int[] dx={0,0,1,-1};
    static int[] dy={1,-1,0,0};//方向向量
    static int n,m,max;
    static boolean[][] visit;//标记
    public int getMaximumGold(int[][] grid) {

        n=grid.length;
        m=grid[0].length;
        visit=new boolean[n][m];
        max=0;
        for(int i=0;i<n;i++) {
            for (int j = 0; j < m; j++) {
                if (grid[i][j] != 0) {
                    for (boolean[] a : visit) {
                        Arrays.fill(a, false);
                    }
                    visit[i][j]=true;
                    max=Math.max(max,grid[i][j]);
                    dfs(grid, i, j, grid[i][j]);
                }
            }
        }
        return max;
    }
    static void dfs(int[][] grid,int i,int j,int s)
    {
        for(int t=0;t<4;t++)
        {
            int x=dx[t]+i;
            int y=dy[t]+j;
            if(x>=0 && x<n && y>=0 && y<m && grid[x][y]!=0 && visit[x][y]==false)
            {
                visit[x][y]=true;
                s+=grid[x][y];
                max=Math.max(max,s);
                dfs(grid,x,y,s);
                s-=grid[x][y];
                visit[x][y]=false;
            }
        }
        return;
    }
}

面试题 08.02. 迷路的机器人

设想有个机器人坐在一个网格的左上角,网格 r 行 c 列。机器人只能向下或向右移动,但不能走到一些被禁止的网格(有障碍物)。设计一种算法,寻找机器人从左上角移动到右下角的路径。

img

网格中的障碍物和空位置分别用 10 来表示。

返回一条可行的路径,路径由经过的网格的行号和列号组成。左上角为 0 行 0 列。如果没有可行的路径,返回空数组。

示例 1:

输入:
[
  [0,0,0],
  [0,1,0],
  [0,0,0]
]
输出: [[0,0],[0,1],[0,2],[1,2],[2,2]]
解释: 
输入中标粗的位置即为输出表示的路径,即
00列(左上角) -> 01-> 02-> 12-> 22列(右下角)

**说明:**rc 的值均不超过 100。

class Solution {
    static int n,m;
    static Deque<List<Integer>> deque;
    static int[] dx=new int[]{0,1};
    static int[] dy=new int[]{1,0};
    static boolean[][] dp;
    static int min;
    public List<List<Integer>> pathWithObstacles(int[][] obstacleGrid) {

        n=obstacleGrid.length;
        m=obstacleGrid[0].length;
        dp=new boolean[n][m];
        for(boolean[] a:dp)
        {
            Arrays.fill(a,true);
        }
        deque=new ArrayDeque<>();
        if(obstacleGrid[0][0]==1 || obstacleGrid[n-1][m-1]==1)
        {
            return deque.stream().toList();
        }


        min=Integer.MAX_VALUE;
        List<Integer> l=new ArrayList<>();
        l.add(0);
        l.add(0);
        deque.add(l);
        if(!dfs(obstacleGrid,0,0))
        {
            deque.removeFirst();
        }
        return deque.stream().toList();
    }
    static boolean dfs(int[][] obstacleGrid,int i, int j)
    {
        //从左上角到右下角,边走边记录当前位置,回退时撤销当前位置
        //因为只能从下走或者从右走,不存在走过已经走过的格子,所以不需要标记数组
        if(dp[i][j]==false)
        {
            return false;
        }

        if(i==n-1 && j==m-1)
        {
            return true;
        }
        for(int t=0;t<2;t++)
        {
            int x=dx[t]+i;
            int y=dy[t]+j;
            if(x<n && y<m && obstacleGrid[x][y]==0)
            {
                List<Integer> list=new ArrayList<>();
                list.add(x);
                list.add(y);
                deque.addLast(list);
                if(dfs(obstacleGrid,x,y))
                {
                    return true;
                }
                else
                    deque.removeLast();
            }
        }
        dp[i][j]=false;
        return false;
    }
}

494. 目标和

494. 目标和

给你一个非负整数数组 nums 和一个整数 target

向数组中的每个整数前添加 '+''-' ,然后串联起所有整数,可以构造一个 表达式

  • 例如,nums = [2, 1] ,可以在 2 之前添加 '+' ,在 1 之前添加 '-' ,然后串联起来得到表达式 "+2-1"

返回可以通过上述方法构造的、运算结果等于 target 的不同 表达式 的数目。

示例 1:

输入:nums = [1,1,1,1,1], target = 3
输出:5
解释:一共有 5 种方法让最终目标和为 3-1 + 1 + 1 + 1 + 1 = 3
+1 - 1 + 1 + 1 + 1 = 3
+1 + 1 - 1 + 1 + 1 = 3
+1 + 1 + 1 - 1 + 1 = 3
+1 + 1 + 1 + 1 - 1 = 3
class Solution {
    int res=0;
    public int findTargetSumWays(int[] nums, int target) {
        dfs(nums,0,0,target);
        return res;
    }
    void dfs(int[] nums,int i,int s,int target)
    {
        if(i==nums.length)
        {
            if(s==target)
                res++;
            return;
        }
        dfs(nums,i+1,s+nums[i],target);
        dfs(nums,i+1,s-nums[i],target);
        return;
    }

}

491. 递增子序列

491. 递增子序列

给你一个整数数组 nums ,找出并返回所有该数组中不同的递增子序列,递增子序列中 至少有两个元素 。你可以按 任意顺序 返回答案。

数组中可能含有重复元素,如出现两个整数相等,也可以视作递增序列的一种特殊情况。

示例 1:

输入:nums = [4,6,7,7]
输出:[[4,6],[4,6,7],[4,6,7,7],[4,7],[4,7,7],[6,7],[6,7,7],[7,7]]
class Solution {
    static int n;
    static List<List<Integer>> res;
    public List<List<Integer>> findSubsequences(int[] nums) {
        res=new ArrayList<>();
        n=nums.length;
        Deque<Integer> deque=new ArrayDeque<>();
        for(int i=2;i<=n;i++)
        {
            dfs(nums,deque,i,0);
        }
        return res;
    }
    static void dfs(int[] nums,Deque<Integer> deque,int k,int c)
    {
        if(deque.size()==k)
        {
            res.add(new ArrayList<>(deque));
            return;
        }
        Set<Integer> set=new HashSet<>();
        for(int i=c;i<n;i++)
        {
            if(set.contains(nums[i]))
            {
                continue;
            }
            set.add(nums[i]);
            if(deque.size()==0 || (deque.size()!=0 && deque.getLast()<=nums[i])) {
                deque.addLast(nums[i]);
                dfs(nums, deque, k, i + 1);
                deque.removeLast();
            }
        }
        return;
    }
}

LCR 157. 套餐内商品的排列顺序

LCR 157. 套餐内商品的排列顺序

某店铺将用于组成套餐的商品记作字符串 goods,其中 goods[i] 表示对应商品。请返回该套餐内所含商品的 全部排列方式

返回结果 无顺序要求,但不能含有重复的元素。

示例 1:

输入:goods = "agew"
输出:["aegw","aewg","agew","agwe","aweg","awge","eagw","eawg","egaw","egwa","ewag","ewga","gaew","gawe","geaw","gewa","gwae","gwea","waeg","wage","weag","wega","wgae","wgea"]
class Solution {
    boolean[] visit;
    int n;
    Set<String> set;
    public String[] goodsOrder(String goods) {
        set=new HashSet<>();
        n=goods.length();
        visit=new boolean[n];
        Deque<Character> str=new ArrayDeque<>();
        dfs(goods,str,0);
        return set.toArray(new String[0]);
    }
    void dfs(String good, Deque<Character> str, int count)
    {

        if(count==n)
        {
            String s="";
            for(Character ch:str)
            {
                s+=ch;
            }
            set.add(s);
            return;
        }
        for(int i=0;i<n;i++)
        {
            if(visit[i]==false)
            {
                visit[i]=true;
                str.addLast(good.charAt(i));
                dfs(good,str,count+1);
                str.removeLast();
                visit[i]=false;
            }

        }
    }

}

17. 电话号码的字母组合

17. 电话号码的字母组合

给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。

给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。

img

示例 1:

输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
class Solution {
    List<String> res=new ArrayList<>();
    String[] str={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    public List<String> letterCombinations(String digits) {
        StringBuilder sb=new StringBuilder();
        if(digits.length()==0)
        {
            return res;
        }
        dfs(digits,sb,0);
        return res;
    }
    void dfs(String digits,StringBuilder sb,int index)
    {
        //判断结束条件
        if(index==digits.length())
        {
            res.add(sb.toString());
            return;
        }
        String s=str[digits.charAt(index)-'0'];
        //选择s中的一个字符
        for(int i=0;i<s.length();i++)
        {
            sb.append(s.charAt(i));
            dfs(digits,sb,index+1);
            //回溯
            sb.deleteCharAt(index);
        }
        return;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值