hot100-贪心 回溯

贪心

121. 买卖股票的最佳时机

解法一、从前往后遍历

class Solution {
    public int maxProfit(int[] prices) {
        int profit = 0;
        int min = Integer.MAX_VALUE;
        for(int i = 0; i < prices.length; i++){
            min = Math.min(prices[i], min);
            profit = Math.max(profit, prices[i] - min);

        }
        return profit;
    }
}

解法二、从后往前遍历 

class Solution {
    public int maxProfit(int[] prices) {
        int res = 0,n = prices.length,max = prices[n-1];
        if(n==1)return 0;
        for(int i = n-2;i >= 0;i--){//从n-2开始
            res = Math.max(res,max-prices[i]);
            max = Math.max(max,prices[i]);
        }
        return res;
    }
}

55. 跳跃游戏

解法一、从前往后

class Solution {
    public boolean canJump(int[] nums) {
        int n = nums.length,max = 0;
        for(int i = 0;i<n;i++){
            if(max < i)return false;
            max = Math.max(max,i+nums[i]);
        }
        return true;
    }
}

解法二、从后往前

class Solution {
    public boolean canJump(int[] nums) {
        int n = nums.length,step = 1;
        for(int i = n - 2;i >= 0;i--){
            if(nums[i] < step){
                step++;
            }else{
                step = 1;
            }
        }
        return step == 1;
    }
}

45. 跳跃游戏 II

解法一、

每次修桥都走到头(即maxNow)

class Solution {
    public int jump(int[] nums) {
        int n = nums.length,max = 0,maxNow = 0,res = 0;
        for(int i = 0;i<n-1;i++){
            if(max < i + nums[i])max = i+nums[i];
            if(i == maxNow && max > maxNow){
                res++;
                maxNow = max;
            }
        }
        return res;
    }
}


763. 划分字母区间

解法一、贪心

①记录尾标

②第二个循环更新尾标,只要i到尾标=可以结束 记载进答案

import java.util.Arrays;
class Solution {
    public List<Integer> partitionLabels(String s) {
        char[] c = s.toCharArray();
        int n = s.length();
        int[] last = new int[26];
        for(int i = 0;i < n;i++){
            last[c[i] - 'a'] = i;
        }
        List<Integer> res = new LinkedList<>();
        int start = 0,end = 0;
        for(int i = 0;i<n;i++){
            end = Math.max(end,last[c[i] - 'a']);
            if(i == end){
                res.add(end - start +1);
                start = i+1;
            }
        }
        return res;
    }
}

回溯

46. 全排列

 解法一、回溯

class Solution {
    private void dfs(int i,int[] nums, List<List<Integer>> res,boolean[] onPath,List<Integer> path){
        if(i == nums.length){
            res.add(new ArrayList<>(path));
            return;
        }
        for(int j = 0; j < nums.length;j++){
            if(!onPath[j]){
                //如果不在里面,那么
                path.set(i,nums[j]);
                onPath[j] = true;
                dfs(i+1,nums,res,onPath,path);
                onPath[j] = false;
            }
        }

    }
    public List<List<Integer>> permute(int[] nums) {
        List<Integer> path = Arrays.asList(new Integer[nums.length]);
        boolean[] onPath = new boolean[nums.length];
        List<List<Integer>> res = new LinkedList<>();
        dfs(0,nums,res,onPath,path);
        return res;
    }
}

78. 子集

 解法一、选或不选

class Solution {
    List<Integer> path = new ArrayList<>();
    List<List<Integer>> res = new LinkedList<>();
    
    private void dfs(int i,int[] nums){
        if(i == nums.length){
            res.add(new ArrayList<>(path));
            return;
        }
        dfs(i+1,nums);
        
        path.add(nums[i]);
        dfs(i+1,nums);
        path.remove(path.size()-1);
    }
    public List<List<Integer>> subsets(int[] nums) {
        dfs(0,nums);
        return res;
    }
}

解法二、选哪个

class Solution {
    List<Integer> path = new ArrayList<>();
    List<List<Integer>> res = new LinkedList<>();

    private void dfs(int i,int[] nums){
        res.add(new ArrayList<>(path));
        for(int j = i;j<nums.length;j++){
            path.add(nums[j]);
            dfs(j+1,nums);
            path.remove(path.size()-1);
        }
    }
    public List<List<Integer>> subsets(int[] nums) {
        dfs(0,nums);
        return res;
    }
}

17. 电话号码的字母组合

解法一、回溯

务必注意处理空的情况

可以考虑把StringBuffer换成一个固定长度为n的char数组

class Solution {
    private String[] a = new String[]{"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
    List<String> res = new ArrayList<>();
    StringBuffer tmp = new StringBuffer();
    public List<String> letterCombinations(String digits) {
        if(digits.equals(""))return res;
        char[] c = digits.toCharArray();
        dfs(0,c);
        return res;
    }
    private void dfs(int i,char[] c){
        if(i == c.length){
            res.add(tmp.toString());
            return;
        }
        String s = a[c[i] - '0'];
        int l = s.length();
        for(int j = 0;j < l;j++){
            tmp.append(s.charAt(j));
            dfs(i+1,c);
            tmp.delete(tmp.length()-1,tmp.length());
        }
    }
}

 
39. 组合总和

 解法一、回溯

class Solution {
    private List<List<Integer>> res = new ArrayList<>();
    private List<Integer> path = new ArrayList<>();
    public List<List<Integer>> combinationSum(int[] candidates, int target) {
        dfs(0,candidates,target);
        return res;
    }
    private void dfs(int i,int[] candidates, int target){
        if(target == 0){
            res.add(new ArrayList<>(path));
            return;
        }
        int l = candidates.length;
        if(i == l)return;
        for(int j = i;j < l;j++){
            if(target>=candidates[j]){
                path.add(candidates[j]);
                dfs(j,candidates,target-candidates[j]);
                path.remove(path.size()-1);
            }
        }
    }
}

22. 括号生成

 解法一、回溯

class Solution {
    private List<String> res = new ArrayList<>();
    private char[] tmp;
    public List<String> generateParenthesis(int n) {
        tmp = new char[2*n];
        dfs(n,0,0,tmp);
        return res;
    }
    private void dfs(int n,int len,int left,char[] tmp){
        if(len == 2*n){
            res.add(new String(tmp));
            return;
        }
        if(left < n){//可以放左
            tmp[len] = '(';
            dfs(n,len+1,left+1,tmp);
        }
        if(left * 2 > len){//可以放右
            tmp[len] = ')';
            dfs(n,len+1,left,tmp);
        }
    }
}

79. 单词搜索

解法一、回溯

需要注意在return false之前要恢复v

优化一:在bfs中可以将board改值,表示已遍历。

优化二:统计一下字母数量,board<word则肯定没有。

优化三:如果首字母远大于尾字母数量,倒悬搜索也可以。

class Solution {
    private int[][] indirection = {{1,0},{-1,0},{0,1},{0,-1}};
    private boolean[][] isVisited;
    public boolean exist(char[][] board, String word) {
        int m = board.length,n = board[0].length;
        isVisited = new boolean[m][n];
        isVisited[0][0] = true;
        Deque<int[]> d = new LinkedList<>();
        d.push(new int[]{0,0});
        while(!d.isEmpty()){
            int[] tmp = d.pop();
            isVisited[tmp[0]][tmp[1]] = true;
            if(board[tmp[0]][tmp[1]] == word.charAt(0)){
                boolean[][] v = new boolean[m][n];
                if(bfs(board,word,1,tmp[0],tmp[1],v))return true;
            }
            if(tmp[0] + 1 < m && !isVisited[tmp[0]+1][tmp[1]])d.push(new int[] { tmp[0]+1,tmp[1]});
            if(tmp[1] + 1 < n&& !isVisited[tmp[0]][tmp[1]+1])d.push(new int[] { tmp[0],tmp[1]+1});
        }
        return false;
    }
    private boolean isValid(int m,int n,int x, int y){
        return x >= 0 && y >= 0 && x < m && y < n;
    }
    public boolean bfs(char[][]board,String word,int i,int x,int y,boolean[][] v){
        if(i == word.length())return true;
        v[x][y] = true;
        int m = board.length,n = board[0].length;
        for(int[] dir : indirection){
            int x1 = x + dir[0];
            int y1 = y + dir[1];
            if(isValid(m,n,x1,y1) && !v[x1][y1] && board[x1][y1] == word.charAt(i)) {
                if(bfs(board,word,i+1,x1,y1,v))return true;
            }
        }
        v[x][y] = false;
        return false;
    }
}

 
131. 分割回文串

 解法一、回溯

res.add的时候忘了复制了

class Solution {
    private List<List<String>> res = new ArrayList<>();
    private List<String> tmp = new ArrayList<>();
    public List<List<String>> partition(String s) {
        dfs(s,0);
        return res;
    }
    private void dfs(String s,int i){
        if(i == s.length()) {
            res.add(new ArrayList<>(tmp));
            return;
        }
        int len = s.length();
        for(int j = i;j < len;j++){
            if(isValid(s,i,j)){
                tmp.add(s.substring(i,j+1));
                dfs(s,j+1);
                tmp.remove(tmp.size()-1);
            }
        }
    }
    private boolean isValid(String s,int x,int y){
        while(x < y){
            if(s.charAt(x++) != s.charAt(y--))return false;
        }
        return true;
    }
}

51. N 皇后

解法一、回溯

三个bool数组判断合理性是精华

import java.util.Arrays;
class Solution {
    private List<List<String>> res = new ArrayList<>();
    public List<List<String>> solveNQueens(int n) {
        int[] queen = new int[n];
        boolean[] col = new boolean[n];
        boolean[] diag1 = new boolean[2 * n - 1];
        boolean[] diag2 = new boolean[2 * n - 1];
        dfs(queen,col,diag1,diag2,0);
        return res;
    }
    private void dfs(int[] queen,boolean[] col,boolean[] diag1,boolean[] diag2,int i){
        int n = queen.length;
        if(i == n){
            List<String> board = new ArrayList<>(n);
            char[] c = new char[i];
            Arrays.fill(c,'.');
            for(int j = 0;j < i;j++){
                c[queen[j]] = 'Q';
                board.add(new String(c));
                c[queen[j]] = '.';
            }
            res.add(new ArrayList<>(board));
            return;
        }
        for(int j = 0;j < n;j++){
            if(!col[j] && !diag1[i+j] && !diag2[j - i + n - 1]){
                queen[i] = j;
                col[j] = true;
                diag1[i + j] = true;//0,0  1,2 2,1
                diag2[j - i + n - 1] = true;
                dfs(queen,col,diag1,diag2,i+1);
                col[j] = diag1[i+j] = diag2[j - i + n - 1] = false;
            }
        }
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值