• LeetCode解题报告—— Word Search & Subsets II & Decode Ways


    1. Word Search

    Given a 2D board and a word, find if the word exists in the grid.

    The word can be constructed from letters of sequentially adjacent cell, where "adjacent" cells are those horizontally or vertically neighboring. The same letter cell may not be used more than once.

    For example,
    Given board =

    [
      ['A','B','C','E'],
      ['S','F','C','S'],
      ['A','D','E','E']
    ]
    

    word = "ABCCED", -> returns true,
    word = "SEE", -> returns true,
    word = "ABCB", -> returns false.

    思路:其实我感觉LeetCode上中等难度的题目大多数都可以用递归和dp来解决。遍历矩阵,如果遇到的这个字符和要匹配的单词中的第一个字符相等,那么接下来是看这个字符的上下左右(不越界的情况)是不是和单词中的第二个字符相等的,以此类推,实际上是在不断循环的调用单个字符是否匹配这个方法,如果匹配则往下层递归,不匹配返回上层,当递归层数等于word字符数时,表明找到完全匹配项了,返回true。剩下一个要注意的点是,避免字符重用,不能出现往上走又往下走这种递归情况。

    class Solution {
        public boolean exist(char[][] board, String word) {
            char[] w = word.toCharArray();
            for (int y=0; y<board.length; y++) {
                for (int x=0; x<board[y].length; x++) {
                    if (exist(board, y, x, w, 0)) return true;
                }
            }
            return false;
        }
        
        private boolean exist(char[][] board, int y, int x, char[] word, int i) {
            if (i == word.length) return true;
            if (y<0 || x<0 || y == board.length || x == board[y].length) return false;
            if (board[y][x] != word[i]) return false;
            board[y][x] = "*";  // 将当前位置设置未一个非字母字符以免后续遍历时再回到此位置时出现重复利用字符的情况
            boolean exist = exist(board, y, x+1, word, i+1)
                || exist(board, y, x-1, word, i+1)
                || exist(board, y+1, x, word, i+1)
                || exist(board, y-1, x, word, i+1);
            board[y][x] = word[i];  // 遍历结束后需置回原来字符
            return exist;
        }
    }

    2. Subsets II

    Given a collection of integers that might contain duplicates, nums, return all possible subsets (the power set).

    Note: The solution set must not contain duplicate subsets.

    For example,
    If nums = [1,2,2], a solution is:

    [
      [2],
      [1],
      [1,2,2],
      [2,2],
      [1,2],
      []
    ]

    思路:Subset题目的改进版,原数组中的元素可以重复,所以难点是怎么处理数组中重复的元素,对于之前数组元素不重复的Subset,解决方法是先排序一遍,从长度0到数组长度n循环递归,加入一个值,再对其后面的数组部分以同样的方法递归。对于本题目,可以确定重复的子集发生的情形是子集长度一样的情况,所以需要再从长度0到数组长度n循环递归中的循环中加一些代码来防止重复。

    public List<List<Integer>> subsetsWithDup(int[] nums) {
        Arrays.sort(nums);
        List<List<Integer>> res = new ArrayList<>();
        List<Integer> each = new ArrayList<>();
        helper(res, each, 0, nums);
        return res;
    }
    public void helper(List<List<Integer>> res, List<Integer> each, int pos, int[] n) {
        if (pos <= n.length) {
            res.add(each);
        }
        int i = pos;
        while (i < n.length) {
            each.add(n[i]);
            helper(res, new ArrayList<>(each), i + 1, n);
            each.remove(each.size() - 1);
            i++;
            while (i < n.length && n[i] == n[i - 1]) {i++;}  // 避免重复
        }
        return;
    }

    The Basic idea is: use “while (i < n.length && n[i] == n[i - 1]) {i++;}” to avoid the duplicate. For example, the input is 2 2 2 3 4. Consider the helper function. The process is:

    • each.add(n[i]); --> add first 2 (index 0)
    • helper(res, new ArrayList<>(each), i + 1, n); --> go to recursion part, list each is <2 (index 0)>
    • while (i < n.length && n[i] == n[i - 1]) {i++;} --> after this, i == 3, add the element as in subset I

    3. Decode Ways

    A message containing letters from A-Z is being encoded to numbers using the following mapping:

    'A' -> 1
    'B' -> 2
    ...
    'Z' -> 26
    

    Given an encoded message containing digits, determine the total number of ways to decode it.

    For example,
    Given encoded message "12", it could be decoded as "AB" (1 2) or "L" (12). The number of ways decoding "12" is 2.

    思路:咋看一下,可以用穷举来解决,那么应该可以使用dp的思路来解决这道题目。确定了是用dp之后,需要确定的数组dp[i]的索引和值的意义,以及是自底向上还是自顶向下。dp[i]代表的是给定的字符串message长度为i时总共有多少种decode方法,这里有一点要注意的是message中可能存在的0。对于这题的dp思路,从左向右,也就是从低向上,先来赋初值。dp[0]=1代表message是空时,encode way只有一种,对于dp[1],即message中的第一个值,如果是0的话decode way的个数是0,否则为1。接下来怎么dp才是难点,对于message中的位置i, 如果这个位置上的数字是1到9的那么这个数字和dp[i-1]是一种组合,如果这个数字和前一个构成的数在10到26之间,那么这两个数字和dp[i-2]又能构成一种decode way。

    import java.util.*;
    
    public class LeetCode{
        public static void main(String[] args){
            Scanner sc=new Scanner(System.in);
            String message=sc.nextLine();
            System.out.println(numDecodings(message));
        }
        
        static int numDecodings(String s){
            if(s==null || s.length()==0) return 0;
            int n=s.length();
            int[] dp=new int[n+1];
            dp[0]=1;
            dp[1]=s.charAt(0)!='0'? 1:0;
            for(int i=2; i<=n; i++){
                int first=Integer.parseInt(s.substring(i-1,i));
                int second=Integer.parseInt(s.substring(i-2,i));
                if(first>=1&&first<=9){
                    dp[i]=dp[i-1];
                }
                if(second>=10&&second<=26){
                    dp[i]+=dp[i-2];   // 要将两种情况计和
                }
            }
            return dp[n];
        }
    }
  • 相关阅读:
    servlet生命周期和线程安全
    如何保证Redis与数据库的数据一致性
    消息队列高可用、幂等性、顺序性、可靠性传输、堆积问题解决
    如何保证消息队列消息的顺序性
    RabbitMQ 如何保证消息不丢失?
    深入理解MySql事务
    MySQL/mariadb知识点总结
    如何实现一个线程安全的单例,前提是不能加锁
    DUBBO原理、应用与面经总结
    SpringBoot中资源初始化加载的几种方式
  • 原文地址:https://www.cnblogs.com/f91og/p/8601801.html
Copyright © 2020-2023  润新知