Java实现LeetCode 题号:671 - 680

177 阅读4分钟

「这是我参与2022首次更文挑战的第13天,活动详情查看:2022首次更文挑战」。

LeetCode习题集 有些题可能直接略过了,整理一下之前刷leetcode

671. 二叉树中第二小的节点

给定一个非空特殊的二叉树,每个节点都是正数,并且每个节点的子节点数量只能为 2 或 0。如果一个节点有两个子节点的话,那么这个节点的值不大于它的子节点的值。

给出这样的一个二叉树,你需要输出所有节点中的第二小的值。如果第二小的值不存在的话,输出 -1 。

示例 1:

输入: 
    2
   / \
  2   5
     / \
    5   7

输出: 5

说明: 最小的值是 2 ,第二小的值是 5 。 示例 2:

输入: 
    2
   / \
  2   2

输出: -1

说明: 最小的值是 2, 但是不存在第二小的值。

PS:
    这里为什么没有用两个变量保存小的值或者大的值
       因为题目描述了当前结点值小于等于他的子节点值,我们可以得知根节点是最小值
       如果当前值不等于根结点的话,那么再找最小的一定是第二小的结点
       
       如果循环完,res还是初始值,并且树的结点也是res这个值,我们可得出没有第二小的值
 
class Solution {
     public int findSecondMinimumValue(TreeNode root) {
        if(root == null){
            return -1;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.add(root);
        int res = 2147483647;
        int flag = 0;
        while(queue.size() != 0){
            for(int i = 0;i < queue.size();i++){
            TreeNode node = queue.poll();
            if(node.val != root.val){
                res = Math.min(res,node.val);
            }
            if(node.val == 2147483647){
                flag = 1;
            }
            
            if(node.left != null){
                queue.add(node.left);
            }
            if(node.right != null){
                queue.add(node.right);
            }    
        }
        }
        if(res == 2147483647 && flag == 0){
            return -1;
        }
        return res;
    }
}

672. 灯泡开关 Ⅱ

现有一个房间,墙上挂有 n 只已经打开的灯泡和 4 个按钮。在进行了 m 次未知操作后,你需要返回这 n 只灯泡可能有多少种不同的状态。

假设这 n 只灯泡被编号为 [1, 2, 3 ..., n],这 4 个按钮的功能如下:

将所有灯泡的状态反转(即开变为关,关变为开) 将编号为偶数的灯泡的状态反转 将编号为奇数的灯泡的状态反转 将编号为 3k+1 的灯泡的状态反转(k = 0, 1, 2, ...) 示例 1:

输入: n = 1, m = 1. 输出: 2 说明: 状态为: [开], [关] 示例 2:

输入: n = 2, m = 1. 输出: 3 说明: 状态为: [开, 关], [关, 开], [关, 关] 示例 3:

输入: n = 3, m = 1. 输出: 4 说明: 状态为: [关, 开, 关], [开, 关, 开], [关, 关, 关], [关, 开, 开]. 注意: n 和 m 都属于 [0, 1000].

PS:



当n=1的时候,当m=1的时候包含全部两种状态,m=2的时候包含全部两种状态,m>2的时候包含m=1的时候的全部状态,所以返回2n=2的时候,当m=1的时候包含3种状态,m=2的时候包含4种状态,m=3包含全部状态,m>3的时候包含m=2的全部状态也就是全部2种状态

当n>2的时候,当m=1的时候包含7种状态,当m=2的时候包含8种状态,m=3的时候包含全部8种状态,m>3的时候包含m=2的全部状态也就是8种状态

class Solution {
       public int flipLights(int n, int m) {
       if(n == 0 || m == 0){
           return 1;
       }
       if(m == 1){
           return n<3 ? n+m:4;
       }
       else if (m == 2 ){
           return n<3 ? n*m:7;
       }
       else{
           return n<3 ? 2*n:8;
       }
   }
}

673. 最长递增子序列的个数

给定一个未排序的整数数组,找到最长递增子序列的个数。

示例 1:

输入: [1,3,5,4,7] 输出: 2 解释: 有两个最长递增子序列,分别是 [1, 3, 4, 7] 和[1, 3, 5, 7]。 示例 2:

输入: [2,2,2,2,2] 输出: 5 解释: 最长递增子序列的长度是1,并且存在5个子序列的长度为1,因此输出5。 注意: 给定的数组长度不超过 2000 并且结果一定是32位有符号整数。

PS:
	普通递推,加一个记录的数组
class Solution {
   public int findNumberOfLIS(int[] nums) {

       
        if (nums.length == 0) {
            return 0;
        }

        int[] dp = new int[nums.length];
        int[] combination = new int[nums.length];

        Arrays.fill(dp, 1);
        Arrays.fill(combination, 1);

        int max = 1, res = 0;

        for (int i = 1; i < dp.length; i++) {
            for (int j = 0; j < i; j++) {
                if (nums[i] > nums[j]) {
                    if (dp[j] + 1 > dp[i]) {  
                        dp[i] = dp[j] + 1;
                        combination[i] = combination[j];
                    } else if (dp[j] + 1 == dp[i]) {  
                        combination[i] += combination[j];
                    }
                }
            }
            max = Math.max(max, dp[i]);
        }

        for (int i = 0; i < nums.length; i++)
            if (dp[i] == max) res += combination[i];

        return res;
    }
}

674. 最长连续递增序列

给定一个未经排序的整数数组,找到最长且连续的的递增序列。

示例 1:

输入: [1,3,5,4,7] 输出: 3 解释: 最长连续递增序列是 [1,3,5], 长度为3。 尽管 [1,3,5,7] 也是升序的子序列, 但它不是连续的,因为5和7在原数组里被4隔开。 示例 2:

输入: [2,2,2,2,2] 输出: 1 解释: 最长连续递增序列是 [2], 长度为1。 注意:数组长度不会超过10000。

PS:
    滑动窗口:
        如果是连续递增的我们就记录长度,
        如果发现不是连续递增了,那么我们从当前位置开始重新计算子数组长度

class Solution {
      public int findLengthOfLCIS(int[] nums) {
        if(nums.length<1){
            return 0;
        }
        int d = 0;
        int max = 1;
        for(int i =1;i<nums.length;i++){
            if(nums[i] > nums[i-1]){
                max = Math.max(i - d + 1,max);
            }else{
                d = i;
            }
        }
        return max;
    }
}

676. 实现一个魔法字典

实现一个带有buildDict, 以及 search方法的魔法字典。

对于buildDict方法,你将被给定一串不重复的单词来构建一个字典。

对于search方法,你将被给定一个单词,并且判定能否只将这个单词中一个字母换成另一个字母,使得所形成的新单词存在于你构建的字典中。

示例 1:

Input: buildDict(["hello", "leetcode"]), Output: Null
Input: search("hello"), Output: False
Input: search("hhllo"), Output: True
Input: search("hell"), Output: False
Input: search("leetcoded"), Output: False

注意:

你可以假设所有输入都是小写字母 a-z。 为了便于竞赛,测试所用的数据量很小。你可以在竞赛结束后,考虑更高效的算法。 请记住重置MagicDictionary类中声明的类变量,因为静态/类变量会在多个测试用例中保留。 请参阅这里了解更多详情。

class MagicDictionary {
   List<String> list;
    /** Initialize your data structure here. */
    public MagicDictionary() {
        list=new ArrayList();
    }
    
    /** Build a dictionary through a list of words */
    public void buildDict(String[] dict) {
       for(int i=0;i<dict.length;i++){
           list.add(dict[i]);
       }
    }
    
    /** Returns if there is any word in the trie that equals to the given word after modifying exactly one character */
    public boolean search(String word) {
        int size=list.size();
        int n=word.length();
        for(int i=0;i<size;i++){
            String cur=list.get(i);
            if(cur.length()==n&&notSameOne(cur,word)){
                 return true;
            }
        } 
        return false; 
    }
    public boolean notSameOne(String str1,String str2){
         int n=str1.length();
         int disCout=0;
         for(int i=0;i<n;i++){
             if(str1.charAt(i)!=str2.charAt(i)){
                 disCout++;
             }
             if(disCout>1) return false; 
         }

         return disCout==1?true:false;  
    }
}

 

677. 键值映射

实现一个 MapSum 类里的两个方法,insert 和 sum。

对于方法 insert,你将得到一对(字符串,整数)的键值对。字符串表示键,整数表示值。如果键已经存在,那么原来的键值对将被替代成新的键值对。

对于方法 sum,你将得到一个表示前缀的字符串,你需要返回所有以该前缀开头的键的值的总和。

示例 1:

输入: insert("apple", 3), 输出: Null
输入: sum("ap"), 输出: 3
输入: insert("app", 2), 输出: Null
输入: sum("ap"), 输出: 5
PS:
    字典树
    按照字典树的格式把字符串放进去,然后每个结点有一个count记录数量
    
   插入的时候搜索到指定的位置,更新count
   getSum的时候,如果搜索到字符串不存在直接返回0,否则求字符串下面的字典树count的总和
class MapSum {
  class TrieNode{
        TrieNode[] children;
        int count;
        public TrieNode(){
            this.children = new TrieNode[26];
            count=0;
        }
    } 
    TrieNode root;
    public MapSum() {
        root = new TrieNode();
    }
    
    public void insert(String key, int val) {
        TrieNode cur = root;
        for(char c:key.toCharArray()){
            if(cur.children[c-'a']==null){
                cur.children[c-'a'] = new TrieNode();
            } 
            cur = cur.children[c-'a'];
        }
        cur.count=val;
    }
    
    public int sum(String prefix) {
        TrieNode cur = root;
        int res=0;
        for(char c:prefix.toCharArray()){
            if(cur.children[c-'a']==null)
                return 0;
            cur = cur.children[c-'a'];
        }
        res=getSum(cur);
        return res;
    }
    public int getSum(TrieNode root){
        int res=root.count;
        for(int i=0;i<26;i++){
            if(root.children[i]!=null){
                res+=getSum(root.children[i]);
            }
        }
        return res;
    }
}

 

678. 有效的括号字符串

给定一个只包含三种字符的字符串:( ,) 和 *,写一个函数来检验这个字符串是否为有效字符串。有效字符串具有如下规则:

任何左括号 ( 必须有相应的右括号 )。 任何右括号 ) 必须有相应的左括号 ( 。 左括号 ( 必须在对应的右括号之前 )。

  • 可以被视为单个右括号 ) ,或单个左括号 ( ,或一个空字符串。 一个空字符串也被视为有效字符串。 示例 1:

输入: "()" 输出: True 示例 2:

输入: "(*)" 输出: True 示例 3:

输入: "(*))" 输出: True 注意:

字符串大小将在 [1,100] 范围内。

class Solution {
   public boolean checkValidString(String s) {
       //两个表示的都是左括号,但是l是星号是右括号的时候
       //r是星号是左括号的时候
        int l = 0;
        int r = 0;
        int len = s.length();
        char[] str = s.toCharArray();
        for(int i=0; i<str.length; i++) {
            if (str[i] == '(') {
                l++;
                r++;
            } else if (str[i] == ')') {
                if (l>0) {
                    l--;
                }
                if (r>0) {
                    r--;
                } else {
                return false;
                }
            } else if (str[i] == '*') {
                if(l>0) l--;
                r++;
            }

        }
        return l<=0 && 0<= r;
    }
}

679. 24 点游戏

你有 4 张写有 1 到 9 数字的牌。你需要判断是否能通过 *,/,+,-,(,) 的运算得到 24。

示例 1:

输入: [4, 1, 8, 7] 输出: True 解释: (8-4) * (7-1) = 24 示例 2:

输入: [1, 2, 1, 2] 输出: False 注意:

除法运算符 / 表示实数除法,而不是整数除法。例如 4 / (1 - 2/3) = 12 。 每个运算符对两个数进行运算。特别是我们不能用 - 作为一元运算符。例如,[1, 1, 1, 1] 作为输入时,表达式 -1 - 1 - 1 - 1 是不允许的。 你不能将数字连接在一起。例如,输入为 [1, 2, 1, 2] 时,不能写成 12 + 12 。

class Solution {
    
   public boolean judgePoint24(int[] nums) {
        double[] aa = new double[nums.length];
        for (int i = 0; i < aa.length; i++) {
            aa[i] = (double) nums[i];
        }
        return fun(aa);
    }

        public static boolean fun(double[] arr) {
        if (arr.length < 2) {
            return Math.abs(arr[0] - 24) < 0.0001;
        }
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr.length; j++) {
                if (j == i) {
                    continue;
                }
                double[] arrr = new double[arr.length - 1];
                int k1 = 0;
                for (int k = 0; k < arr.length; k++) {
                    if (k != i && k != j) {
                        arrr[k1++] = arr[k];
                    }
                }
                for (int m = 0; m < 4; m++) {
                    if (m == 0) {
                        arrr[k1] = arr[i] + arr[j];
                    }
                    if (m == 1) {
                        arrr[k1] = arr[i] - arr[j];
                    }
                    if (m == 2) {
                        arrr[k1] = arr[i] * arr[j];
                    }
                    if (m == 3) {
                        if (arr[j] != 0) {
                            arrr[k1] = arr[i] / arr[j];
                        } else {
                            continue;
                        }
                    }
                    if (fun(arrr)) {
                        return true;
                    }
                }
            }
        }
        return false;
    }
}

680. 验证回文字符串 Ⅱ

给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。

示例 1:

输入: "aba" 输出: True 示例 2:

输入: "abca" 输出: True 解释: 你可以删除c字符。 注意:

字符串只包含从 a-z 的小写字母。字符串的最大长度是50000。

PS:
	我只允许有一次跳过,终止条件加上了wrongCount 》=2
class Solution {
       public boolean validPalindrome(String s) {
        if( s == null || s.isEmpty()) {
        	return true;
        }
        
        return validPalindrome(s, 0, s.length()-1, 0);
    }
	
	public boolean validPalindrome(String s, int left, int right, int wrongCount) {
		if( wrongCount >= 2) {
	    	return false;
	    }
        while( left < right) {
        	if( s.charAt(left) == s.charAt(right)) {
        		left++;
        		right--;
        	}else {
        		return validPalindrome(s, left, right-1, wrongCount+1)
        				|| validPalindrome(s, left + 1, right, wrongCount + 1);
        	} 
        }
        return true;
    }
}