文章目录
第一题: 109. 有序链表转换二叉搜索树
LeetCode: 109. 有序链表转换二叉搜索树
描述:
给定一个单链表的头节点 head
,其中的元素 按升序排序 ,将其转换为高度平衡的二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差不超过 1。
解题思路:
- 这里也是使用二分法, 每次去找中间的节点
- 然后中间节点的左半分为左子树, 右半分为右子树
- 递归的去链接起来
- 注意每次需要把左子树最后一个节点的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
。
叶子节点 是指没有子节点的节点。
解题思路:
- 递归的进入 如果当前节点是叶子节点, 且targetSum为0, 就返回true, 否则就是false
- 遍历到一个节点的时候, 就让targetSum减去该节点值.
- 然后递归的进入左右子树.寻找是否有满足要求的叶子节点.
- 如果递归到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,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。
注意:输出结果可能非常大,所以你需要返回一个字符串而不是整数
解题思路:
- 这里将所有的数都转成字符串 加入到优先级队列中.
- 这里堆顶放的是组合起来更大的.
(o2+o1).compare(o1+o2)
- 入堆完之后,再每次都出堆顶元素, 然后用字符串拼接起来.
- 如果最后的结果字符串, 首字符是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, 如果是1就让颠倒位置为1. 为0就让颠倒位置为0
- 注意这里的运算配合使用
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
。
解题思路:
- 首先, 如果数组长度小于3, 直接为false
- 初始化
first = nums[0]
,second = Integer.MAX_VALUE
- 遍历当前数组
- 如果当前数组元素>second, 表示存在第三大的元素, 返回true
- 如果当前数组元素 > first, 表示有第二大的元素, 让second = 该元素
- 如果是其他情况, 移动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 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。
解题思路:
- 首先将两个数组排序.
- 定义两个指针, 分别指向两个指针的初始下标.
- 如果两个指针下的元素相等, 那么就把这个结果添加到结果集中.
- 如果第一个数组的元素大于第二个数组的元素, 那么就让第二个数组找更大的, 让该下标++
- 如果第一个数组的元素小于第二个数组的元素, 那么就让第一个数组找更大的, 让该下标++;
代码实现:
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 。返回这一子串的长度。
解题思路:
- 记录当前字符串中每个字符出现的次数.
- 再次遍历, 如果当前的字符串中有一个字符出现的次数小于k
- 那么就分治的方法,去查看左边是否满足, 满足的最大值. 再去查看右边是否满足, 满足的最大值.
- 最终记录左右两边的最大值.
代码实现:
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();
}
}