力扣逻辑积累题

找规律题动态规划贪心算法,树的题递归。多总结规律题,内核都是规律逻辑。用例子用手推出规律才是重点,实现不重要。

在这里插入图片描述

1.arr[i] i j count
2.a.找到第一个大于等于他的数的位置j
b 从i循环到j,count+=min(i,j)-arr[i]
例子:1-2 取最小min(1,2), 2-3取2:a如果中间有值,减去中间的。
c更新i
3 i=len-1

public int trap(int[] height) {
    int ans = 0;
    int size = height.length;
    for (int i = 1; i < size - 1; i++) {
        int max_left = 0, max_right = 0;
        for (int j = i; j >= 0; j--) { //Search the left part for max bar size
            max_left = Math.max(max_left, height[j]);
        }
        for (int j = i; j < size; j++) { //Search the right part for max bar size
            max_right = Math.max(max_right, height[j]);
        }
        ans += Math.min(max_left, max_right) - height[i];
    }
    return ans;
}

 

在这里插入图片描述

class Solution {
    public int trap(int[] height) {
        int res = 0, h1 = 0, h2 = 0;
        for (int i = 0, j = height.length - 1; i < height.length && j >= 0; i++, j--) {
            h1 = Math.max(h1, height[i]); 
            h2 = Math.max(h2, height[j]);
            res += h1 + h2 - height[i]; // 红色面积 + 蓝色面积 - 黑色面积
        }
        return res - height.length * h1; // 再减去整个矩形面积
    }
}

 

在这里插入图片描述
请添加图片描述

class Solution {
    public int maxCoins(int[] nums) {
        int n = nums.length;
        int[][] dp = new int[n + 2][n + 2];
        int[] val = new int[n + 2];
        val[0] = val[n + 1] = 1;
        for (int i = 1; i <= n; i++) {
            val[i] = nums[i - 1];
        }
        for (int i = n - 1; i >= 0; i--) {//从后到前,慢慢加多,分解法
            for (int j = i + 2; j <= n + 1; j++) {
                for (int k = i + 1; k < j; k++) {//k是i、j中间的
                    int sum = val[i] * val[k] * val[j];
                    sum += dp[i][k] + dp[k][j];
                    dp[i][j] = Math.max(dp[i][j], sum);
                    System.out.println(dp[i][j]);
                }
            }
        }
        return dp[0][n + 1];
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package com.sydx.aqsc.ctrl;

public class Main {
    public static void main(String[] args) {
        isScramble("great",  "rgeat");
    }

        public static boolean isScramble(String s1, String s2) {
            char[] chs1 = s1.toCharArray();
            char[] chs2 = s2.toCharArray();
            int n = s1.length();
            int m = s2.length();
            if (n != m) {
                return false;
            }
            boolean[][][] dp = new boolean[n][n][n + 1];
            // 初始化单个字符的情况
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    dp[i][j][1] = chs1[i] == chs2[j];
                }
            }

            // 枚举区间长度 2~n
            for (int len = 2; len <= n; len++) {
                // 枚举 S 中的起点位置
                for (int i = 0; i <= n - len; i++) {
                    // 枚举 T 中的起点位置
                    for (int j = 0; j <= n - len; j++) {
                        // 枚举划分位置
                        for (int k = 1; k <= len - 1; k++) {
                            // 第一种情况:S1 -> T1, S2 -> T2
                            if (dp[i][j][k] && dp[i + k][j + k][len - k]) {
                                dp[i][j][len] = true;
                                break;
                            }
                            // 第二种情况:S1 -> T2, S2 -> T1
                            // S1 起点 i,T2 起点 j + 前面那段长度 len-k ,S2 起点 i + 前面长度k
                            if (dp[i][j + len - k][k] && dp[i + k][j][len - k]) {
                                dp[i][j][len] = true;
                                break;
                            }
                        }
                    }
                }
            }
            return dp[0][0][n];
        }




}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package com.sydx.aqsc.ctrl;
import java.util.*;


public class Main {
    public static void main(String[] args) {
        List<String> r=new ArrayList<>();
        r.add("cat");
        r.add("cats");
        r.add("and");
        r.add("sand");
        r.add("dog");
        wordBreak("catsanddog",r);
    }

    public static List<String>  wordBreak(String s, List<String> wordDict) {
        // 为了快速判断一个单词是否在单词集合中,需要将它们加入哈希表
        Set<String> wordSet = new HashSet<>(wordDict);
        int len = s.length();

        // 第 1 步:动态规划计算是否有解
        // dp[i] 表示「长度」为 i 的 s 前缀子串可以拆分成 wordDict 中的单词
        // 长度包括 0 ,因此状态数组的长度为 len + 1
        boolean[] dp = new boolean[len + 1];
        // 0 这个值需要被后面的状态值参考,如果一个单词正好在 wordDict 中,dp[0] 设置成 true 是合理的
        dp[0] = true;

        for (int right = 1; right <= len; right++) {//双指针划分区域
            // 如果单词集合中的单词长度都不长,从后向前遍历是更快的
            for (int left = right - 1; left >= 0; left--) {
                // substring 不截取 s[right],dp[left] 的结果不包含 s[left]
                if (wordSet.contains(s.substring(left, right)) && dp[left]) {//核心:区间包含在字典里而且左边也包含的。
                    dp[right] = true;//给右边坐标设置。dp[i] 表示「长度」为 i 的 s 前缀子串可以拆分成 wordDict 中的单词
                    // 这个 break 很重要,一旦得到 dp[right] = True ,不必再计算下去
                    break;
                }
            }
        }

        // 第 2 步:回溯算法搜索所有符合条件的解
        List<String> res = new ArrayList<>();
        if (dp[len]) {
            Deque<String> path = new ArrayDeque<>();
            dfs(s, len, wordSet, dp, path, res);
            return res;
        }
        return res;
    }

    /**递归树调用方式
     * s[0:len) 如果可以拆分成 wordSet 中的单词,把递归求解的结果加入 res 中
     *
     * @param s
     * @param len     长度为 len 的 s 的前缀子串
     * @param wordSet 单词集合,已经加入哈希表
     * @param dp      预处理得到的 dp 数组
     * @param path    从叶子结点到根结点的路径
     * @param res     保存所有结果的变量
     */
    private static void dfs(String s, int len, Set<String> wordSet, boolean[] dp, Deque<String> path, List<String> res) {
        if (len == 0) {//为零代表就可以分割完毕。
            res.add(String.join(" ",path));//路径转成字符串存进结果
            return;
        }

        // 可以拆分的左边界从 len - 1 依次枚举到 0,依次从后向前截取。
        for (int i = len - 1; i >= 0; i--) {
            String suffix = s.substring(i, len);//截取i到尾处
            if (wordSet.contains(suffix) && dp[i]) {//dp用来记忆,减少重复运算,判断该位置可以分割字符串而且包含前缀才进行递归,不符合条件的就进不去。
                path.addFirst(suffix);
                dfs(s, i, wordSet, dp, path, res);//改变len递归求解
                path.removeFirst();//每次结束只需要删掉第一个,进去递归几次就删除几次,最后留下dog,维护
            }
        }
    }




}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述1.dp[i][j]
2.
3.i j<len

class Solution {
    public int minDistance(String word1, String word2) {
        int n = word1.length();
        int m = word2.length();

        // 有一个字符串为空串
        if (n * m == 0) {
            return n + m;
        }

        // DP 数组
        int[][] D = new int[n + 1][m + 1];

        // 边界状态初始化
        for (int i = 0; i < n + 1; i++) {
            D[i][0] = i;
        }
        for (int j = 0; j < m + 1; j++) {
            D[0][j] = j;
        }

        // 计算所有 DP 值
        for (int i = 1; i < n + 1; i++) {
            for (int j = 1; j < m + 1; j++) {
                int left = D[i - 1][j] + 1;
                int down = D[i][j - 1] + 1;
                int left_down = D[i - 1][j - 1];
                if (word1.charAt(i - 1) != word2.charAt(j - 1)) {
                    left_down += 1;
                }
                D[i][j] = Math.min(left, Math.min(down, left_down));
            }
        }
        return D[n][m];
    }
}
 

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

1.dp[i][j](代表出现的不同情况的组合下的解,比如dp[0][1]代表 字符串a 和ca有几个最大公共字符串) str reverse maxEnd maxLen
2.a反转字符串:寻找最长公共子串 b 比较如果相等
b1.dp[i][0]=1, dp[0][j]=1,初始值
b2.dp[i]=dp[i - 1][j - 1] + 1;求最大,递推公式
3.i j

public String longestPalindrome(String s) {
    if (s.equals(""))
        return "";
    String origin = s;
    String reverse = new StringBuffer(s).reverse().toString(); //字符串倒置
    int length = s.length();
    int[][] arr = new int[length][length];
    int maxLen = 0;
    int maxEnd = 0;
    for (int i = 0; i < length; i++)
        for (int j = 0; j < length; j++) {
            if (origin.charAt(i) == reverse.charAt(j)) {
                if (i == 0 || j == 0) {
                    arr[i][j] = 1;
                } else {
                    arr[i][j] = arr[i - 1][j - 1] + 1;
                }
            }
            if (arr[i][j] > maxLen) { 
                maxLen = arr[i][j];
                maxEnd = i; //以 i 位置结尾的字符
            }
        }
	}
	return s.substring(maxEnd - maxLen + 1, maxEnd + 1);
}
 
暴力求解,列举所有的子串,判断是否为回文串,保存最长的回文串。
 public boolean isPalindromic(String s) {
		int len = s.length();
		for (int i = 0; i < len / 2; i++) {
			if (s.charAt(i) != s.charAt(len - i - 1)) {
				return false;
			}
		}
		return true;
	}

 
public String longestPalindrome(String s) {
    String ans = "";
    int max = 0;
    int len = s.length();
    for (int i = 0; i < len; i++)
        for (int j = i + 1; j <= len; j++) {
            String test = s.substring(i, j);
            if (isPalindromic(test) && test.length() > max) {
                ans = s.substring(i, j);
                max = Math.max(max, ans.length());
            }
        }
    return ans;
}

 

在这里插入图片描述
1.string i count
2.判断i和i+1是否配对,a是则i+2,继续判断 b不是则i+1,继续判断
DP思路
1.string i count
2. a if判断i是)
b if 例子1(情况1):i-1是(,dp=2;
if 例子2(情况2):i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == ‘(’) 则 dp[i] = dp[i - 1] + 2;
if 例子三:i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == ‘(’)
则 dp[i] = dp[i - 1] + 2;
3.i=len-1
在这里插入图片描述
在这里插入图片描述
有几个例子就有几个if语句,画出例子实现例子。代码就是代表了逻辑结构,注意嵌套还是并列的。嵌套(分步)是if前面条件一样后面分支,并列(分类)是if前后完全不一样

class Solution {
    public int longestValidParentheses(String s) {
        int maxans = 0;
        int[] dp = new int[s.length()];
        for (int i = 1; i < s.length(); i++) {
            if (s.charAt(i) == ')') {
                if (s.charAt(i - 1) == '(') {
                   		 dp[i] = (i >= 2 ? dp[i - 2] : 0) + 2;
                } else if (i - dp[i - 1] > 0 && s.charAt(i - dp[i - 1] - 1) == '(') {
                    if (i - dp[i - 1]-2 > 0 )
                    	dp[i] = dp[i - 1] + dp[i - dp[i - 1] - 2]  + 2;
                    else 	dp[i] = dp[i - 1]   + 2;
                }
                maxans = Math.max(maxans, dp[i]);
            }
        }
        return maxans;
    }
}

 

360必须写例子在这里插入图片描述

在这里插入图片描述
思路会了就行
1.l1 l2 jinwei_nowjinwei_pre
2.a 反转两个链表:递归方式
b.同时对两个链表更新,并创建结果链表
if加起来 大于10,jinwei_now=1
else 两个节点和+jinwei_pre
c 更新变量jinwei_pre=jinwei_now l1.next l2.next
3. if一个链表为null,另一个全加

错误:没看清题,不需要反转链表

官方思路
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

1.arr[][]

在这里插入图片描述
1.新建 2.添加队列3出狗,first 4出猫 5.出任意

class AnimalShelf {
    

    LinkedList<int[]> queueCat;
    LinkedList<int[]> queueDog;

    public AnimalShelf() {
        queueCat = new LinkedList<>();
        queueDog = new LinkedList<>();
    }

    public void enqueue(int[] animal) {
        // 判断种类后入队
        if (animal[1] == 0) {
            queueCat.addLast(animal);
        } else if (animal[1] == 1) {
            queueDog.addLast(animal);
        }
    }

    public int[] dequeueAny() {
        // 取出cat的队首,判空则直接返回
        int[] headCat;
        if (!queueCat.isEmpty()) {
            headCat = queueCat.getFirst();
        } else if (!queueDog.isEmpty()) {
            return queueDog.removeFirst();
        } else {
            return new int[]{-1,-1};
        }
        // 取出dog的队首,判空则直接返回
        int[] headDog;
        if (!queueDog.isEmpty()) {
            headDog = queueDog.getFirst();
        } else {
            return queueCat.removeFirst();
        }
        // 比较后返回
        if (headCat[0]<=headDog[0]) {
            return queueCat.removeFirst();
        } else {
            return queueDog.removeFirst();
        }
    }

    public int[] dequeueDog() {
        if (!queueDog.isEmpty()) {
            return queueDog.removeFirst();
        } else {
            return new int[]{-1,-1};
        }
    }

    public int[] dequeueCat() {
        if (!queueCat.isEmpty()) {
            return queueCat.removeFirst();
        } else {
            return new int[]{-1,-1};
        }
    }
}

 

在这里插入图片描述1.arr[][] i j path
2.a if是1结束,b 是0则添加path,if是最后一个网格, c更新ij
3.len
在这里插入图片描述

class Solution {
    public List<List<Integer>> pathWithObstacles(int[][] obstacleGrid) {
        LinkedList<List<Integer>> list = new LinkedList<>();
        dfs(obstacleGrid, list, 0, 0);
        return list;
    }
    public boolean dfs(int[][] obstacleGrid,LinkedList<List<Integer>> list, int x, int y){
        if(x < 0 || x >= obstacleGrid.length || 
           y < 0 || y >= obstacleGrid[0].length || 
           obstacleGrid[x][y] != 0){
               return false;
           }
           obstacleGrid[x][y] = 1;                //设置为访问过
           list.add(Arrays.asList(x,y));          //添加这个点
           if(x == obstacleGrid.length - 1 && y == obstacleGrid[0].length - 1){
               return true;           //到终点了
           }
           if(dfs(obstacleGrid, list, x+1, y)){   //是否这条路径可以到终点
               return true;
           }
           if(dfs(obstacleGrid, list, x, y+1)){   //是否这条路径可以到终点
               return true;
           }
           list.removeLast();                    //从这个点出发无法到达终点,移除这个点
           return false;
    }
}

 if 结束条件
 else 操作 更新

在这里插入图片描述在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

1.定义问题的递归函数,明确函数的功能,我们定义这个函数的功能为:把 A 上面的 n 个圆盘经由 B 移到 C
2.关系公式:move(n from A to C) = move(n-1 from A to B) + move(A to C) + move(n-1 from B to C`)
分析可得,我们分三步走。
(1)先把A上的n-1个圆盘,通过和C的操作移动到B上。
(2)把A剩下的最大的一个盘移动到C。
(3)再把B上的n-1个盘,通过和A的操作移动到C上。
不管怎么移动问题和子问题的关系都可以是这三步,下面就可以开始递归。

 
class Solution {
    public void hanota(List<Integer> A, List<Integer> B, List<Integer> C) {
        //得到盘子总数
        int n =A.size();
        func(n,A,B,C);
    }
    public void func(int n,List<Integer> A, List<Integer> B, List<Integer> C){
        //当盘子都移动空了之后停止递归
        if(n<=0){
            return;
        }
        else{
        //将A上面的 n-1 个圆盘经由 C 移到 B
        func(n-1,A,C,B); 
        //此时将 A 底下的那块最大的圆盘移到 C
        C.add(A.remove(A.size()-1));
        // 再将 B 上的 n-1 个圆盘经由A移到 C上
        func(n-1,B,A,C);
        } 
    }
}

 
 
package 计算机程序算法分类.二叉树问题;
 
import 牛客网练习题.Solution;
 
/**
 * @Classname 有序数组转变二叉搜索树108
 * @Description TODO
 * @Date 2021/4/30 14:09
 * @Created by xjl
 */
public class 有序数组转变二叉搜索树108 {
    public class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
 
        public TreeNode(int val) {
            this.val = val;
        }
    }
 
    public TreeNode sortedArrayToBST(int[] nums) {
        return helper(nums, 0, nums.length - 1);
    }
 
    public TreeNode helper(int[] nums, int left, int right) {
        if (left > right) {
            return null;
        }
 
        // 总是选择中间位置左边的数字作为根节点
        int mid = (left + right) / 2;
 
        TreeNode root = new TreeNode(nums[mid]);
        root.left = helper(nums, left, mid - 1);
        root.right = helper(nums, mid + 1, right);
        return root;
    }
 
    public TreeNode sortedArrayToBSTTest(int[] nums) {
        return buidtree(nums, 0, nums.length - 1);
    }
 
    private TreeNode buidtree(int[] nums, int left, int right) {
        if (left > right) {
            return null;
        }
        int mid = left + (right - left) / 2;
        TreeNode node = new TreeNode(nums[mid]);
        node.left = buidtree(nums, left, mid - 1);
        node.right = buidtree(nums, mid + 1, right);
        return node;
    }
 
}

在这里插入图片描述
在这里插入图片描述

class Solution {
    public int pathSum(TreeNode root, int targetSum) {
        if (root == null) {
            return 0;
        }

        int ret = rootSum(root, targetSum);
        ret += pathSum(root.left, targetSum);
        ret += pathSum(root.right, targetSum);
        return ret;
    }

    public int rootSum(TreeNode root, int targetSum) {
        int ret = 0;

        if (root == null) {
            return 0;
        }
        int val = root.val;
        if (val == targetSum) {
            ret++;
        } 

        ret += rootSum(root.left, targetSum - val);
        ret += rootSum(root.right, targetSum - val);
        return ret;
    }
}
 

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

class Solution {
    Map<Integer, Integer> prefixMap;
    int target;

    public int pathSum(TreeNode root, int sum) {
        prefixMap = new HashMap<>();
        target = sum;

        prefixMap.put(0, 1);
        return recur(root, 0);
    }

    private int recur(TreeNode node, int curSum) {
        if(node == null) {
            return 0;
        }

        int res = 0;
        curSum += node.val;

        res += prefixMap.getOrDefault(curSum - target, 0);
        prefixMap.put(curSum, prefixMap.getOrDefault(curSum, 0) + 1);

        int left = recur(node.left, curSum);
        int right = recur(node.right, curSum);

        res = res + left + right;

        prefixMap.put(curSum, prefixMap.get(curSum) - 1);

        return res;
    }
}

 

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
操作逻辑: 遍历字符串1.ip2.掩码3.网段。
在这里插入图片描述

在这里插入图片描述

import java.util.*;
import java.io.*;
public class Main{
    public static void main(String[] args) throws IOException{
        BufferedReader bf = new BufferedReader(new InputStreamReader(System.in));
        int[] count = new int[7];
        String in;
        while ((in = bf.readLine()) != null) {
            //以~分隔
            String[] split=in.split("~");
            String ip=split[0];//获取IP地址
            String mask=split[1];//获取子网掩码

            String[] ips = ip.split("\\.");
            int num1 = 0;
            int num2 = 0;
            try{
                num1=Integer.parseInt(ips[0]);
                num2=Integer.parseInt(ips[1]);
                Integer.parseInt(ips[2]);
                Integer.parseInt(ips[3]);
            }catch(NumberFormatException e){
                count[5]++;
                continue;
            }


            //1、先判IP地址是否合法
            boolean isIP=isIP(ip);
            boolean isMask=isMask(mask);
            //如果IP和子网掩码都合法 就判断是哪种类型的IP地址
            if(isIP && isMask){
                count = countIP(ip,count);
            }else if((isIP == false || isMask == false) &&num1 != 127 && num1 != 0) {
                count[5]++;
            }
        }
        for(int i=0;i<6;i++)
            System.out.print(count[i]+" ");
        System.out.print(count[6]);
    }

    //判断IP是否合法
    public static boolean isIP(String IP){
        //1. 类似于【0.*.*.*】和【127.*.*.*】的IP地址不属于上述输入的任意一类,也不属于不合法ip地址,计数时可以忽略
        String[] IParr = IP.split("\\.");
        Boolean isTrue = true;
        for (int i = 0; i < IParr.length; i++) {
            if (IParr[i].length() <= 0 || IParr[i] == "") {//非法判断
                isTrue = false;
            }
        }
        return isTrue;
    }
    //判断子网掩码是否合法
    public static boolean isMask(String mask){
        String[] maskarr = mask.split("\\.");
        boolean result = false;
        //0000 0000~ 1111 1110 八位
        //子网掩码为二进制下前面是连续的1,然后全是0。(例如:255.255.255.32就是一个非法的掩码)
        // 注意二进制下全是1或者全是0均为非法
        int[] maskRange = {254, 252, 248, 240, 224, 192, 128, 0};
        List<Integer> list = new ArrayList();
        for(int i:maskRange)
            list.add(i);
        //255.255.255.
        if ("255".equals(maskarr[0])&&"255".equals(maskarr[1])&&"255".equals(maskarr[2])) {
            if (list.contains(Integer.parseInt(maskarr[3]))) {
                result=true;
            }
        }
        //255.255.
        else if("255".equals(maskarr[0])&&"255".equals(maskarr[1])){
            if(list.contains(Integer.parseInt(maskarr[2]))&&"0".equals(maskarr[3])){
                result=true;
            }
        }
        //255.
        else if("255".equals(maskarr[0])){
            if(list.contains(Integer.parseInt(maskarr[1]))&&"0".equals(maskarr[2])&&"0".equals(maskarr[3])){
                result=true;
            }
        }else if(list.contains(Integer.parseInt(maskarr[0]))){
            if("0".equals(maskarr[1])&&"0".equals(maskarr[2])&&"0".equals(maskarr[3])){
                result=true;
            }
        }
        return result;
    }//method end

    //私有IP判断
    /*10.0.0.0-10.255.255.255  172.16.0.0-172.31.255.255  192.168.0.0-192.168.255.255*/
    public static boolean isPrivateIP(String IP){
        String[] split = IP.split("\\.");
        //根据范围即可
        if(Integer.parseInt(split[0])==10) return true;
        else if(Integer.parseInt(split[0])==172&&(Integer.parseInt(split[1])>15&&Integer.parseInt(split[1])<32)){
            return true;
        }else if(Integer.parseInt(split[0])==192&&Integer.parseInt(split[1])==168){
            return true;
        }else{
            return false;
        }
    }
    //各类ip计数
    public static int[] countIP(String IP,int[] count){
        String[] split = IP.split("\\.");
        int first=Integer.parseInt(split[0]);
        //如果是私有ip
        if(isPrivateIP(IP)) count[6]++;

        //判断其他地址范围
/*        A类地址1.0.0.0~126.255.255.255;
        B类地址128.0.0.0~191.255.255.255;
        C类地址192.0.0.0~223.255.255.255;
        D类地址224.0.0.0~239.255.255.255;
        E类地址240.0.0.0~255.255.255.255*/
        if (first >= 1 && first <= 126)
            count[0]++;
        else if (first >= 128 && first <= 191)
            count[1]++;
        else if (first >= 192 && first <= 223)
            count[2]++;
        else if (first >= 224 && first <= 239)
            count[3]++;
        else if (first >= 240 && first <= 255)
            count[4]++;
        return count;
    }

}


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import java.util.Set;
import java.util.TreeSet;

/*
* 解密9*9数独:
* 格子内填充1-9的数字(空格用0代替),使任意格子的行,列,九宫格都出现1-9的数字
* 例:
* 8 0 0 0 0 0 0 0 0
* 0 0 3 6 0 0 0 0 0
* 0 7 0 0 9 0 2 0 0
* 0 5 0 0 0 7 0 0 0
* 0 0 0 0 4 5 7 0 0
* 0 0 0 1 0 0 0 3 0
* 0 0 1 0 0 0 0 6 8
* 0 0 8 5 0 0 0 1 0
* 0 9 0 0 0 0 4 0 0
* 结果:
* 8 1 2 7 5 3 6 4 9 
* 9 4 3 6 8 2 1 7 5 
* 6 7 5 4 9 1 2 8 3 
* 1 5 4 2 3 7 8 9 6 
* 3 6 9 8 4 5 7 2 1 
* 2 8 7 1 6 9 5 3 4 
* 5 2 1 9 7 4 3 6 8 
* 4 3 8 5 2 6 9 1 7 
* 7 9 6 3 1 8 4 5 2 
*/
public class Main {

    static int[][] source = new int[9][9];//原始数组

    static int[][] target = new int[9][9];//结果数组

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        /*
         * 空格从最上面的行开始,逐行从左向右填充数值
        */
        Integer firstX = null;//第一个空格的行号
        Integer firstY = null;//第一个空格的列号

        /*
        * 数组录入输入的数字,并获得第一个空格的行号和列号
        */
        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                int c = scanner.nextInt();
                source[i][j] = c;
                target[i][j] = c;
                if(firstX==null && firstY==null && source[i][j]==0){
                    firstX = i;
                    firstY = j;
                }
            }
        }
        
        //开始遍历填充
        go(firstX,firstY);

        //打印结果数组
        for(int i=0;i<9;i++){
            for(int j=0;j<9;j++){
                System.out.print(target[i][j]+" ");
            }
            System.out.println("");
        }
    }

    public static void go(int x,int y){
        boolean flag = build(x,y);//填充

        if(flag){//填充成功,获取下一个空格的行号和列号,以源数组为参照
            do{
                if(x==8&&y==8){//最后的空格填充完毕,结束填充
                    return;
                }
                if(y==8){
                    y=0;
                    x=x+1;
                }else{
                    y=y+1;
                }
            }while(source[x][y]!=0);
        }else{//填充失败,获取上一个空格的行号和列号,以源数组为参照(因为上一个空格已被填充过,所以需要以源数组作为参照)
            do{
                if(x==0&&y==0){//退到第一个空格且无可填充的值,证明无解,结束
                    return;
                }
                if(y==0){
                    y=8;
                    x=x-1;
                }else{
                    y=y-1;
                }
            }while(source[x][y]!=0);
        }
        /*
        * 1.如果当前空格填充成功,则填充的是下一个空格
        * 2.如果当前空格填充失败,则对上一个已填充的空格重新填充
        */
        go(x,y);
    }

    /*
    * 1.填充时,优先填充1-9中的较小值
    * 2.填充时,会有两种情况:1.新空格填充,空格值等于0 2.因后续空格无法继续填充,老空格
    *   尝试填充新的值,再进行后续空格填充
    * 3.经过填充后,空格没有获得新值,说明已无合适数字进行填充,需要将空格重置成0,返回f-
    *   -alse对上一空格进行重新填充
    * 4.经过填充后,空格获得新值,返回true根据结果判断对后续空格进行填充
    */
    public static boolean build(int x,int y){
        int r = target[x][y];
        for(int n=r+1;n<10;n++){
            target[x][y] = n;
            if(isExists(x,y)){
                target[x][y] = r;
            }else{
                break;
            }
        }
        if(target[x][y]==r){
            target[x][y]=0;//已无可填充数字,将格子重置成0,并重新填充上一个格子
            return false;
        }else{
            return true;
        }
    }

    //判断当前空格的值是否已存在于同行,同列或同九宫格的其他格子中
    public static boolean isExists(int x,int y){
        Set<Integer> set = getExists(x,y);
        return set.contains(target[x][y]);
    }
    //获取当前格子的行,列,九宫格中已填充的数字
    public static Set getExists(int x, int y){
        Set<Integer> set = new TreeSet<Integer>();
        for(int i=0;i<9;i++){
            if(i==x){
                continue;
            }
            if(target[i][y]==0){
                continue;
            }
            set.add(target[i][y]);
        }
        for(int i=0;i<9;i++){
            if(i==y){
                continue;
            }
            if(target[x][i]==0){
                continue;
            }
            set.add(target[x][i]);
        }
        int xn = x/3;
        int yn = y/3;
        for(int i=xn*3;i<xn*3+3;i++){
            for(int j=yn*3;j<yn*3+3;j++){
                if(i==x&&j==y){
                    continue;
                }
                if(target[i][j]==0){
                    continue;
                }
                set.add(target[i][j]);
            }
        }
        return set;
    }

}


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import java.util.*;
import java.lang.*;

public class Main{
    private static final String ERROR = "ERROR";

    private static final String NONE = "NONE";

    private static Map<Integer, String> map2 = new HashMap<Integer, String>() {
        {
            put(2, "2");
            put(3, "3");
            put(4, "4");
            put(5, "5");
            put(6, "6");
            put(7, "7");
            put(8, "8");
            put(9, "9");
            put(10, "10");
            put(1, "A");
            put(11, "J");
            put(12, "Q");
            put(13, "K");
        }
    };

    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);

        Map<String, Integer> map = new HashMap<String, Integer>() {
            {
                put("2", 2);
                put("3", 3);
                put("4", 4);
                put("5", 5);
                put("6", 6);
                put("7", 7);
                put("8", 8);
                put("9", 9);
                put("10", 10);
                put("A", 1);
                put("J", 11);
                put("Q", 12);
                put("K", 13);
                put("joker", 0);
                put("JOKER", 0);
            }
        };
        while (in.hasNext()) {
            List<Integer> list = new ArrayList<>();
            for (int i = 0; i < 4; i++) {
                String str = in.next();
                list.add(map.get(str));
            }
            if (list.contains(0)) {
                System.out.println(ERROR);
            } else {
                String sb = new String("");
                boolean flag = false;
                boolean[] used = new boolean[list.size()];
                for (int i = 0; i < list.size(); i++) {
                    sb = String.valueOf(map2.get(list.get(i)));
                    used[i] = true;
                    if (helper(list, 1, sb, list.get(i), i, used)) {
                        flag = true;
                        break;
                    }
                    used[i] = false;
                }
                if (!flag) {
                    System.out.println(NONE);
                }
            }

        }
    }
    private static boolean helper(List<Integer> list, int cnt, String result, int temp, int i, boolean[] used) {
        if (cnt == 4) {
            if (temp == 24) {
                System.out.println(result);
            }
            return temp == 24;
        }
        for (int j = 0; j < list.size(); j++) {
            if (used[j]) {
                continue;
            }
            used[j] = true;
            int y = list.get(j);
            if (helper(list, cnt + 1, result + "+" + map2.get(y), temp + y, i, used)) {
                return true;
            }
            if (helper(list, cnt + 1, result + "-" + map2.get(y), temp - y, i, used)) {
                return true;
            }
            if (helper(list, cnt + 1, result + "*" + map2.get(y), temp * y, i, used)) {
                return true;
            }

            if (y != 0 && helper(list, cnt + 1, result + "/" + map2.get(y), temp / y, i, used)) {
                return true;
            }
            used[j] = false;

        }
        return false;
    }
}

在这里插入图片描述
在这里插入图片描述

 
class Solution {
    public List<String> binaryTreePaths(TreeNode root) {
        List<String> paths = new ArrayList<String>();
        constructPaths(root, "", paths);
        return paths;
    }

    public void constructPaths(TreeNode root, String path, List<String> paths) {
        if (root != null) {
            StringBuffer pathSB = new StringBuffer(path);
            pathSB.append(Integer.toString(root.val));
            if (root.left == null && root.right == null) {  // 当前节点是叶子节点
                paths.add(pathSB.toString());  // 把路径加入到答案中
                 System.out.println(pathSB);
            } else {
                pathSB.append("->");  // 当前节点不是叶子节点,继续递归遍历
                        System.out.println(pathSB);
                constructPaths(root.left, pathSB.toString(), paths);
                constructPaths(root.right, pathSB.toString(), paths);
            }
        }
    }
}
 

## 加入path1.叶子节点2.不是叶子,递归,回溯恢复

class Solution {
    String path="";
    List<String> paths = new ArrayList<String>();
    public List<String> binaryTreePaths(TreeNode root) {
        constructPaths(root);
        return paths;
    }
    public void constructPaths(TreeNode root ) {
        if (root != null) {
            StringBuffer pathSB = new StringBuffer(path);
            pathSB.append(Integer.toString(root.val));
            if (root.left == null && root.right == null) {  // 当前节点是叶子节点
                paths.add(pathSB.toString());  // 把路径加入到答案中
                 System.out.println(pathSB);
            } else {
                String pat=path;
                pathSB.append("->");  // 当前节点不是叶子节点,继续递归遍历
                        System.out.println(pathSB);
                        path=pathSB.toString();
                constructPaths(root.left );
                constructPaths(root.right );
                path=pat;
            }
        }
    }
}
 

在这里插入图片描述
在这里插入图片描述

class Solution {
    static int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    int[][] grid;
    int m, n;
    int ans = 0;

    public int getMaximumGold(int[][] grid) {
        this.grid = grid;
        this.m = grid.length;
        this.n = grid[0].length;
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (grid[i][j] != 0) {
                    dfs(i, j, 0);
                }
            }
        }
        return ans;
    }

    public void dfs(int x, int y, int gold) {
        gold += grid[x][y];
        ans = Math.max(ans, gold);

        int rec = grid[x][y];
        grid[x][y] = 0;

        for (int d = 0; d < 4; ++d) {
            int nx = x + dirs[d][0];
            int ny = y + dirs[d][1];
            if (nx >= 0 && nx < m && ny >= 0 && ny < n && grid[nx][ny] > 0) {
                dfs(nx, ny, gold);
            }
        }

        grid[x][y] = rec;
    }
}
超时
class Solution {
    public int getMaximumGold(int[][] grid) {
        m = grid.length;
        n = grid[0].length;
        this.grid = grid;
        //1. 每个格子检查一遍,每个非0格子都可以作为是一条路径的起点
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                //2. 可以作为起点的格子,试试能不能走出更好的路径,更好就替换掉当前的最好路径
                if(grid[i][j]!=0)
                    dfs(i,j,0);
            }
        }
        return ans;
    }
    int[][] grid;
    int m;
    int n;
    int ans=0;
    int[] directions = new int[]{0,1,0,-1,0};
    private void dfs(int x, int y, int gold){
         if(!(x>=0&&x<m&&y>=0&&y<n&&grid[x][y] > 0)){
                return;
         }
        gold += grid[x][y];
        System.out.println(gold);
        ans = Math.max(ans, gold);
        int rec = grid[x][y];
        //3. 走过的格子,先标记为0(代表第二次不可达),尝试完该格子后,再恢复(因为对于前一个格子来说,它是可达,换个方向,进入该格子也是可达,为了换方向再次经过该格子后,能拿到正确的值,第一次查过后,应该恢复原本的值)
        grid[x][y] = 0;
        dfs(x+1,y,gold);          
        dfs(x-1,y,gold);            
        dfs(x,y+1,gold);         
        dfs(x,y-1,gold);      
        //3. 走过的格子,先标记为0(代表第二次不可达),尝试完该格子后,再恢复(因为对于前一个格子来说,它是可达,换个方向,进入该格子也是可达,为了换方向再次经过该格子后,能拿到正确的值,第一次查过后,应该恢复原本的值)
        grid[x][y] = rec;
    }
}
 

在这里插入图片描述
在这里插入图片描述

class Solution {

    public int calculateMinimumHP(int[][] dungeon) {
        return dfs(dungeon, dungeon.length, dungeon[0].length, 0, 0);
    }

    private int dfs(int[][] dungeon, int m, int n, int i, int j) {
        // 到达终点,递归终止。
        if (i == m - 1 && j == n - 1) {
            return Math.max(1 - dungeon[i][j], 1);
        }
        // 最后一行,只能向右搜索。
        if (i == m - 1) {
            return Math.max(dfs(dungeon, m, n, i, j + 1) - dungeon[i][j], 1);
        }
        // 最后一列,只能向下搜索。
        if (j == n - 1) {
           return Math.max(dfs(dungeon, m, n, i + 1, j) - dungeon[i][j], 1);
        }
        // 向下搜索 + 向右搜索,得到(i, j)点的后续路径所要求的最低血量 Math.min(dfs(i + 1, j), dfs(i, j + 1)),
        // 又因为(i, j)点本身提供血量dungeon[i][j], 因此从(i, j)开始所需的最低血量为 Math.min(dfs(i + 1, j), dfs(i, j + 1)) - dungeon[i][j]
        // 因为骑士的血量不能小于1,因此要和1取个max。
        return Math.max(Math.min(dfs(dungeon, m, n, i + 1, j), dfs(dungeon, m, n, i, j + 1)) - dungeon[i][j], 1);
    }
}

 class Solution {
    int[][] memo; // 定义记忆化数组
    public int calculateMinimumHP(int[][] dungeon) {
        memo = new int[dungeon.length][dungeon[0].length];
        return dfs(dungeon, dungeon.length, dungeon[0].length, 0, 0);
    }

    private int dfs(int[][] dungeon, int m, int n, int i, int j) {
        // 到达终点,递归终止。
        if (i == m - 1 && j == n - 1) {
            return Math.max(1 - dungeon[i][j], 1);
        }
        // 如果memo数组中有值,直接取出并返回,不进行后续的搜索。
        if (memo[i][j] > 0) {
            return memo[i][j];
        }
        // 同解法一,向右搜+向下搜
        int minRes = 0;
        if (i == m - 1) {
            minRes =  Math.max(dfs(dungeon, m, n, i, j + 1) - dungeon[i][j], 1);
        } else if (j == n - 1) {
            minRes = Math.max(dfs(dungeon, m, n, i + 1, j) - dungeon[i][j], 1);
        } else {
            minRes = Math.max(Math.min(dfs(dungeon, m, n, i + 1, j), dfs(dungeon, m, n, i, j + 1)) - dungeon[i][j], 1);
        }
        // 将结果存入memo数组
        return memo[i][j] = minRes;
    }
}
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值