每日刷题记录 (二十二)

x33g5p2x  于2022-07-14 转载在 其他  
字(4.1k)|赞(0)|评价(0)|浏览(396)

第一题: 109. 有序链表转换二叉搜索树

LeetCode: 109. 有序链表转换二叉搜索树
描述:
给定一个单链表的头节点 head ,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1。

解题思路:

  1. 这里也是使用二分法, 每次去找中间的节点
  2. 然后中间节点的左半分为左子树, 右半分为右子树
  3. 递归的去链接起来
  4. 注意每次需要把左子树最后一个节点的next置空

代码实现:

class Solution {
    public TreeNode sortedListToBST(ListNode head) {
        if(head == null) return null;
        if(head.next == null) return new TreeNode(head.val);
        ListNode fast = head;
        ListNode slow = head;
        ListNode pre = null;
        while(fast != null && fast.next != null) {
            fast = fast.next.next;
            pre = slow;
            slow = slow.next;
        }
        pre.next = null;
        TreeNode root = new TreeNode(slow.val);
        root.left = sortedListToBST(head);
        root.right = sortedListToBST(slow.next);
        return root;
    }
}

第二题: 112. 路径总和

LeetCode: 112. 路径总和

描述:
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false

叶子节点 是指没有子节点的节点。

解题思路:

  1. 递归的进入 如果当前节点是叶子节点, 且targetSum为0, 就返回true, 否则就是false
  2. 遍历到一个节点的时候, 就让targetSum减去该节点值.
  3. 然后递归的进入左右子树.寻找是否有满足要求的叶子节点.
  4. 如果递归到root为空, 说明就没有满足条件的, 返回false;

代码实现:

class Solution {
    public boolean hasPathSum(TreeNode root, int targetSum) {
        if(root == null) return false;
        if(root.left == null && root.right == null) {
            if(root.val == targetSum) {
                return true;
            }else{
                return false;
            }
        }
        targetSum -= root.val;
        return hasPathSum(root.left, targetSum) || hasPathSum(root.right,targetSum);
    }
}

第三题: 179. 最大数

LeetCode: 179. 最大数

描述:
给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。

注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数

解题思路:

  1. 这里将所有的数都转成字符串 加入到优先级队列中.
  2. 这里堆顶放的是组合起来更大的. (o2+o1).compare(o1+o2)
  3. 入堆完之后,再每次都出堆顶元素, 然后用字符串拼接起来.
  4. 如果最后的结果字符串, 首字符是0, 那么直接返回 "0"

代码实现:

class Solution {
    public String largestNumber(int[] nums) {
        PriorityQueue<String> pq = new PriorityQueue<>((o1,o2) -> ((o2+o1).compareTo(o1+o2)));
        for(int num : nums) {
            pq.offer(num+"");
        }
        StringBuilder res = new StringBuilder();
        while(!pq.isEmpty()) {
            res.append(pq.poll());
        }
        if(res.charAt(0) == '0') return "0";
        return res.toString();
    }
}

第四题: 190. 颠倒二进制位

LeetCode: 190. 颠倒二进制位

描述:
颠倒给定的 32 位无符号整数的二进制位。

提示:

  • 请注意,在某些语言(如 Java)中,没有无符号整数类型。在这种情况下,输入和输出都将被指定为有符号整数类型,并且不应影响您的实现,因为无论整数是有符号的还是无符号的,其内部的二进制表示形式都是相同的。
  • 在 Java 中,编译器使用二进制补码记法来表示有符号整数。因此,在 示例 2 中,输入表示有符号整数 -3,输出表示有符号整数 -1073741825。

解题思路:

  1. 这里直接使用位运算
  2. 求得每一位是否是1, 如果是1就让颠倒位置为1. 为0就让颠倒位置为0
  3. 注意这里的运算配合使用 res |= (n & 1) << (31-i)

代码实现:

public class Solution {
    // you need treat n as an unsigned value
    public int reverseBits(int n) {
        int res = 0;
        for(int i = 0; i < 32; i++) {
            res |= (n & 1) << (31-i);
            n>>=1;
        }
        return res;
    }
}

第五题: 334. 递增的三元子序列

LeetCode: 334. 递增的三元子序列

描述:

给你一个整数数组 nums ,判断这个数组中是否存在长度为 3 的递增子序列。

如果存在这样的三元组下标 (i, j, k) 且满足 i < j < k ,使得 nums[i] < nums[j] < nums[k] ,返回 true ;否则,返回 false

解题思路:

  1. 首先, 如果数组长度小于3, 直接为false
  2. 初始化 first = nums[0], second = Integer.MAX_VALUE
  3. 遍历当前数组
  4. 如果当前数组元素>second, 表示存在第三大的元素, 返回true
  5. 如果当前数组元素 > first, 表示有第二大的元素, 让second = 该元素
  6. 如果是其他情况, 移动first的位置.

代码实现:

class Solution {
    public boolean increasingTriplet(int[] nums) {
        if(nums.length < 3) return false;
        int first = nums[0];
        int second = Integer.MAX_VALUE;
        for(int num : nums) {
            if(num > second) {
                return true;
            }else if(num > first) {
                second = num;
            }else{
                first = num;
            }
        }
        return false;
    }
}

第六题: 350. 两个数组的交集 II

LeetCode: 350. 两个数组的交集 II

描述:
给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。

解题思路:

  1. 首先将两个数组排序.
  2. 定义两个指针, 分别指向两个指针的初始下标.
  3. 如果两个指针下的元素相等, 那么就把这个结果添加到结果集中.
  4. 如果第一个数组的元素大于第二个数组的元素, 那么就让第二个数组找更大的, 让该下标++
  5. 如果第一个数组的元素小于第二个数组的元素, 那么就让第一个数组找更大的, 让该下标++;

代码实现:

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        List<Integer> list = new ArrayList<>();
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        int i1 = 0;
        int i2 = 0;
        while(i1 < nums1.length && i2 < nums2.length) {
            if(nums1[i1] == nums2[i2]){
                list.add(nums1[i1]);
                i1++;
                i2++;
            }else if(nums1[i1] > nums2[i2]){
                i2++;
            }else{
                i1++;
            }
        }
        int[] res = new int[list.size()];
        for(int i = 0; i < list.size(); i++) {
            res[i] = list.get(i);
        }
        return res;
    }
}

第七题: 395. 至少有 K 个重复字符的最长子串

LeetCode: 395. 至少有 K 个重复字符的最长子串

描述:
给你一个字符串 s 和一个整数 k ,请你找出 s 中的最长子串, 要求该子串中的每一字符出现次数都不少于 k 。返回这一子串的长度。

解题思路:

  1. 记录当前字符串中每个字符出现的次数.
  2. 再次遍历, 如果当前的字符串中有一个字符出现的次数小于k
  3. 那么就分治的方法,去查看左边是否满足, 满足的最大值. 再去查看右边是否满足, 满足的最大值.
  4. 最终记录左右两边的最大值.

代码实现:

class Solution {
    public int longestSubstring(String s, int k) {
        int[] arr = new int[26];
        if(s.length() < k) return 0;
        for(char ch : s.toCharArray()) {
            arr[ch-'a']++;
        }
        for(int i = 0; i < s.length(); i++) {
            if(arr[s.charAt(i)-'a'] < k) {
                int left = longestSubstring(s.substring(0,i),k);
                int right = longestSubstring(s.substring(i+1,s.length()),k);
                return Math.max(left,right); 
            }
        }
        return s.length();
    }
}

相关文章