《腾讯精选练习50题》专题

1. 力扣2 两数相加

https://leetcode.cn/problems/add-two-numbers/

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode p1 = l1;
        ListNode p2 = l2;
        ListNode dummy = new ListNode(-1);
        ListNode p3 = dummy;
        boolean mark = false;
        while(p1 != null || p2 != null){
            int num1 = 0;
            int num2 = 0;
            if(p1 != null){
                num1 = p1.val;
                p1 = p1.next;
            }
            if(p2 != null){
                num2 = p2.val;
                p2 = p2.next;
            }
            int sum = num1 + num2;
            if(mark){
                sum++;
                mark = false;
            }
            if(sum >= 10){
                mark = true;
                sum -= 10;
            }
            p3.next = new ListNode(sum);
            p3 = p3.next;
        }
        if(mark){
            p3.next = new ListNode(1);
        }
        return dummy.next;
    }
}

2. 力扣4 寻找两个正序数组的中位数

https://leetcode.cn/problems/median-of-two-sorted-arrays/

思路:

    要求时间复杂度O(log(n)),不能排序,只能二分查找。

    没什么思路,参照官方题解写的。

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int n = nums1.length + nums2.length;
        int k = n / 2;
        if(n % 2 == 1){
            return findKthMin(nums1, nums2, k + 1);
        } else{
            return (findKthMin(nums1, nums2, k) + findKthMin(nums1, nums2, k + 1)) / 2.0;
        }
    }

    public double findKthMin(int[] nums1, int[] nums2, int k){
        int n1 = nums1.length;
        int n2 = nums2.length;
        int p1 = 0;
        int p2 = 0;
        
        while(true){
            if(p1 == n1){
                return nums2[p2 + k - 1];
            }
            if(p2 == n2){
                return nums1[p1 + k - 1];
            }
            if(k == 1){
                return Math.min(nums1[p1], nums2[p2]);
            }

            int ck = k / 2;
            int k1 = Math.min(p1 + ck, n1) - 1;
            int k2 = Math.min(p2 + ck, n2) - 1;
            if(nums1[k1] <= nums2[k2]){
                k -= k1 - p1 + 1;
                p1 = k1 + 1;
            } else{
                k -= k2 - p2 + 1;
                p2 = k2 + 1;
            }
        }
    }
}

3. 力扣5 最长回文子串

https://leetcode.cn/problems/longest-palindromic-substring/

思路:

    暴力求解。

class Solution {
    public String longestPalindrome(String s) {
        String res = "";
        // 遍历字符串s
        for(int i = 0; i < s.length(); i++){
            String str1 = getPalindrome(s, i, i);
            String str2 = getPalindrome(s, i, i + 1);
            String str = str1.length() > str2.length() ? str1 : str2;
            res = str.length() > res.length() ? str : res;
        }
        return res;
    }

    /**
     * 获得以某两点为中心的最长子回文串
     */
    public String getPalindrome(String s, int left, int right){
        while(left >= 0 && right < s.length() && s.charAt(left) == s.charAt(right)){
            left--;
            right++;
        }
        return s.substring(left + 1, right);
    }
}

4. 力扣7 整数反转

https://leetcode.cn/problems/reverse-integer/

思路:

    这道题的卡点在于判断结果是否超出有符号整数范围。

class Solution {
    public int reverse(int x) {
        int res = 0;
        while(x != 0){
            if(res < Integer.MIN_VALUE / 10 || res > Integer.MAX_VALUE / 10){
                return 0;
            }
            int curr = x % 10;
            res = res * 10 + curr;
            x /= 10;
        }
        return res;
    }
}

5. 力扣8 字符串转换整数

https://leetcode.cn/problems/string-to-integer-atoi/

class Solution {
    boolean b2 = true;

    public int myAtoi(String s) {
        String str1 = work1(s);
        String str2 = work2(str1); 
        String str3 = work3(str2);
        long long4 = work4(str3);
        int int5 = work5(long4);
        
        return int5;
    }

    public String work1(String s){
        return s.trim();
    }

    public String work2(String s){
        if("".equals(s)){
            return s;
        }
        char c = s.charAt(0);
        if(c == '-'){
            b2 = false;
        }
        if(c == '-' || c == '+'){
            return s.substring(1);
        }
        return s;
    }

    public String work3(String s){
        int n = s.length();
        int i = 0;
        boolean firstNot0 = false;
        StringBuilder sb = new StringBuilder();
        while(i < n){
            char c = s.charAt(i);
            if(c >= '0' && c <= '9'){
                if(c > '0'){
                    firstNot0 = true;
                 }
                if(c != '0' || firstNot0){
                    sb.append(c);
                }
                i++;
            } else{
                break;
            }
        }
        if(sb.length() == 0){
            sb.append('0');
        }
        return sb.toString();
    }

    public long work4(String s){
        // 防止s超出long类型的取值范围
        if(s.length() > 10){
            return b2 ? Integer.MAX_VALUE : Integer.MIN_VALUE;
        }
        long l = Math.abs(Long.valueOf(s));
        return b2 ? l : -l;
    }

    public int work5(long l){
        if(l < Integer.MIN_VALUE){
            l = Integer.MIN_VALUE;
        }
        if(l > Integer.MAX_VALUE){
            l = Integer.MAX_VALUE;
        }
        return (int) l;
    }
}

6. 力扣9 回文数

https://leetcode.cn/problems/palindrome-number/

思路:

    将数字高低位倒过来,如果和原来的大小相等,就是回文数。

class Solution {
    public boolean isPalindrome(int x) {
        if(x < 0){
            return false;
        }
        int d = x;
        int sum = 0;
        while(x != 0){
            int curr = x % 10;
            sum = sum * 10 + curr;
            x /= 10;
        }
        return sum == d;
    }
}

7. 力扣11 盛最多水的容器

https://leetcode.cn/problems/container-with-most-water/

思路:

    双指针法。如果知道要使用双指针法,很容易写出代码,问题是,为什么这道题可以使用双指针法?

    对撞双指针,每次都让两个指针中指向的值较小的指针移动,因为,假如指向较小值的指针固定,无论另外一个指针移动多少步,得到的盛水量都不可能大于当前盛水量。

class Solution {
    public int maxArea(int[] height) {
        int l = 0;
        int r = height.length - 1;
        int max = 0;
        while(l <= r){
            int curr = (r - l) * Math.min(height[l], height[r]);
            if(curr > max){
                max = curr;
            }
            if(height[l] < height[r]){
                l++;
            }else{
                r--;
            }
        }
        return max;
    }
}

8. 力扣14 最长公共前缀

https://leetcode.cn/problems/longest-common-prefix/

class Solution {
    public String longestCommonPrefix(String[] strs) {
        boolean f = true;
        StringBuilder sb = new StringBuilder();
        int k = 0;
        while(f){
            if(k >= strs[0].length()){
                break;
            }
            char c = strs[0].charAt(k);
            for(int i = 1; i < strs.length; i++){
                if(k >= strs[i].length() || strs[i].charAt(k) != c){
                    f = false;
                    break;
                }
            }
            if(f){
                sb.append(c);
                k++;
            }
        }
        return sb.toString();
    }
}

9. 力扣15 三数之和

https://leetcode.cn/problems/3sum/submissions/

思路:

    先排序。定下第一个值,剩下两个值使用对撞指针。

class Solution {
    public List<List<Integer>> threeSum(int[] nums) {
        int n = nums.length;
        List<List<Integer>> res = new LinkedList();
        Arrays.sort(nums);
        int p1 = 0;
        while(p1 < n - 2){
            if(p1 > 0 && nums[p1] == nums[p1 - 1]){
                p1++;
                continue;
            }
            int target = -nums[p1];
            int p2 = p1 + 1;
            int p3 = n - 1;
            while(p2 < p3){
                if(p2 > p1 + 1 && nums[p2] == nums[p2 - 1]){
                    p2++;
                    continue;
                }
                int sum = nums[p2] + nums[p3];
                if(target > sum){
                    p2++;
                } else if(target < sum){
                    p3--;
                } else{
                    List<Integer> list = new LinkedList();
                    list.add(nums[p1]);
                    list.add(nums[p2]);
                    list.add(nums[p3]);
                    res.add(list);
                    p2++;
                }
            }
            p1++;
        }
        return res;
    }
}

10. 力扣16 最接近的三数之和

https://leetcode.cn/problems/3sum-closest/

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        int n = nums.length;
        Arrays.sort(nums);
        int res = Integer.MAX_VALUE;
        int minDert = Integer.MAX_VALUE;
        int p1 = 0;
        while(p1 < n - 2){
            int currTarget = target - nums[p1];
            int p2 = p1 + 1;
            int p3 = n - 1;
            while(p2 < p3){
                int sum = nums[p2] + nums[p3];
                if(sum == currTarget){
                    return target;
                }
                int dert = Math.abs(sum - currTarget);
                if(dert < minDert){
                    minDert = dert;
                    res = sum + nums[p1];
                }
                if(sum < currTarget){
                    p2++;
                }
                if(sum > currTarget){
                    p3--;
                }
            }
            p1++;
        }
        return res;
    }
}

11. 力扣20 有效的括号

https://leetcode.cn/problems/valid-parentheses/

思路:

    使用栈。

class Solution {
    public boolean isValid(String s) {
        int n = s.length();
        Stack<Character> stack = new Stack();
        for(int i = 0; i < n; i++){
            char c = s.charAt(i);
            if(c == '(' || c == '[' || c == '{'){
                stack.push(c);
            } else{
                if(stack.isEmpty()){
                    return false;
                }
                char d = stack.pop();
                if(c == ')' && d != '('){
                    return false;
                }
                if(c == ']' && d != '['){
                    return false;
                }
                if(c == '}' && d != '{'){
                    return false;
                }
            }
        }
        return stack.isEmpty();
    }
}

12. 力扣21 合并两个有序链表

https://leetcode.cn/problems/merge-two-sorted-lists/

class Solution {
    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode dummy = new ListNode(-1);
        ListNode curr = dummy;
        while(list1 != null && list2 != null){
            if(list1.val <= list2.val){
                curr.next = list1;
                list1 = list1.next;
            } else{
                curr.next = list2;
                list2 = list2.next;
            }
            curr = curr.next;
        }
        if(list1 != null){
            curr.next = list1;
        }
        if(list2 != null){
            curr.next = list2;
        }
        return dummy.next;
    }
}

13. 力扣23 合并K个升序链表

https://leetcode.cn/problems/merge-k-sorted-lists/

思路:

    把所有链表放在一个队列中,每次取出两个链表进行合并,再将合并后的链表放回队列,直到剩下一个链表。

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        int n = lists.length;
        ListNode res = null;
        Queue<ListNode> queue = new LinkedList();
        for(int i = 0; i < n; i++){
            queue.offer(lists[i]);
        }
        while(!queue.isEmpty()){
            ListNode node1 = queue.poll();
            if(queue.isEmpty()){
                res = node1;
                break;
            }
            ListNode node2 = queue.poll();
            queue.offer(mergeTwoLists(node1, node2));
        }
        return res;
    }

    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode dummy = new ListNode(-1);
        ListNode curr = dummy;
        while(list1 != null && list2 != null){
            if(list1.val <= list2.val){
                curr.next = list1;
                list1 = list1.next;
            } else{
                curr.next = list2;
                list2 = list2.next;
            }
            curr = curr.next;
        }
        if(list1 != null){
            curr.next = list1;
        }
        if(list2 != null){
            curr.next = list2;
        }
        return dummy.next;
    }
}

14. 力扣26 删除有序数组中的重复项

https://leetcode.cn/problems/remove-duplicates-from-sorted-array/

思路:

    快慢指针。

class Solution {
    public int removeDuplicates(int[] nums) {
        int n = nums.length;
        int fast = 1;
        int slow = 0;
        while(fast < n){
            if(nums[fast] != nums[slow]){
                swap(nums, slow + 1, fast);
                slow++;
            }
            fast++;
        }
        return slow + 1;
    }

    public void swap(int[] nums, int a, int b){
        int t = nums[a];
        nums[a] = nums[b];
        nums[b] = t;
    }
}

15. 力扣33 搜索旋转排序数组

https://leetcode.cn/problems/search-in-rotated-sorted-array/

思路:

    二分搜索。每次取中点会将区间分成两部分,一部分有序,另一部分为旋转排序数组,如果target不在有序的一边,就在另一边,以此缩小区间。

class Solution {
    public int search(int[] nums, int target) {
        int n = nums.length;
        int left = 0;
        int right = n - 1;
        while(left <= right){
            int mid = left + (right - left) / 2;
            if(target == nums[mid]){
                return mid;
            }
            if(nums[mid] >= nums[left]){
                if(target < nums[mid] && target >= nums[left]){
                    right = mid - 1;
                } else{
                    left = mid + 1;
                }
            } else{
                if(target > nums[mid] && target <= nums[right]){
                    left = mid + 1;
                } else{
                    right = mid - 1;
                }
            }
        }
        return -1;
    }
}

16. 力扣43 字符串相乘

https://leetcode.cn/problems/multiply-strings/

思路:

    十分暴力的暴力法。

class Solution {
    public String multiply(String num1, String num2) {
        int[] intnum1 = strToIntArr(num1);
        int[] intnum2 = strToIntArr(num2);

        String[] resArr = new String[intnum2.length];
        for(int i = 0; i < intnum2.length; i++){
            resArr[i] = intArrToString(multiplyOne(intnum1, intnum2[i]), i);
        }

        String res = "";
        for(int i = 0; i < resArr.length; i++){
            res = strAdd(res, resArr[i]);
        }

        return res;
    }

    public String strAdd(String num1, String num2){
        int[] intnum1 = strToIntArr(num1);
        int[] intnum2 = strToIntArr(num2);
        int size = Math.max(intnum1.length, intnum2.length) + 1;

        int[] res = new int[size];
        int tmp = 0;
        for(int i = 0; i < res.length; i++){
            int addnum1 = i < intnum1.length ? intnum1[i] : 0;
            int addnum2 = i < intnum2.length ? intnum2[i] : 0;
            int sum = addnum1 + addnum2 + tmp;
            res[i] = sum % 10;
            tmp = sum / 10;
        }
        return intArrToString(res, 0);
    }

    public int[] strToIntArr(String str){
        int n = str.length();
        int[] res = new int[n];
        for(int i = 0; i < n; i++){
            res[n - 1 - i] = str.charAt(i) - '0';
        }
        return res; // 倒序
    }

    public int[] multiplyOne(int[] num, int k){
        int n = num.length;
        int tmp = 0;
        int[] res = new int[n + 1];
        for(int i = 0; i < n; i++){
            int r = num[i] * k + tmp;
            res[i] = r % 10;
            tmp = r / 10;
        }
        res[n] = tmp;
        return res;
    }

    public String intArrToString(int[] num, int move){
        StringBuilder sb = new StringBuilder();
        int start = num.length - 1;
        while(start >= 0){
            if(num[start] == 0){
                start--;
                continue;
            }
            break;
        }
        while(start >= 0){
            sb.append(num[start]);
            start--;
        }
        while(move > 0){
            sb.append('0');
            move--;
        }
        if(sb.isEmpty()){
            sb.append('0');
        }
        return sb.toString();
    }
}

17. 力扣46 全排列

https://leetcode.cn/problems/permutations/

思路:

    一眼回溯。

class Solution {
    List<List<Integer>> res;
    List<Integer> tool;
    boolean[] used;

    public List<List<Integer>> permute(int[] nums) {
        res = new LinkedList();
        tool = new LinkedList();
        used = new boolean[nums.length];
        backtrack(nums, used);
        return res;
    }

    public void backtrack(int[] nums, boolean[] used){
        if(tool.size() == nums.length){
            res.add(new LinkedList(tool));
            return;
        }
        for(int i = 0; i < nums.length; i++){
            if(!used[i]){
                tool.add(nums[i]);
                used[i] = true;
                backtrack(nums, used);
                tool.remove(tool.size() - 1);
                used[i] = false;
            }
        }
    }
}

18. 力扣53 最大子数组和

https://leetcode.cn/problems/maximum-subarray/

思路:

    一次遍历,当sum<0时,重新将sum置为0。

class Solution {
    public int maxSubArray(int[] nums) {
        int n = nums.length;
        int res = Integer.MIN_VALUE;
        int sum = 0;
        for(int i = 0; i < n; i++){
            sum += nums[i];
            res = Math.max(res, sum);
            if(sum < 0){
                sum = 0;
            }
        }
        return res;
    }
}

19. 力扣54 螺旋矩阵

https://leetcode.cn/problems/spiral-matrix/

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        int h = matrix.length;
        int w = matrix[0].length;
        int upper_bound = 0;
        int lower_bound = h - 1;
        int left_bound = 0;
        int right_bound = w - 1;
        List<Integer> res = new ArrayList();
        while(res.size() < h * w){
            if(upper_bound <= lower_bound){
                for(int i = left_bound; i <= right_bound; i++){
                    res.add(matrix[upper_bound][i]);
                }
                upper_bound++;
            }
            if(right_bound >= left_bound){
                for(int i = upper_bound; i <= lower_bound; i++){
                    res.add(matrix[i][right_bound]);
                }
                right_bound--;
            }
            if(lower_bound >= upper_bound){
                for(int i = right_bound; i >= left_bound; i--){
                    res.add(matrix[lower_bound][i]);
                }
                lower_bound--;
            }
            if(left_bound <= right_bound){
                for(int i = lower_bound; i >= upper_bound; i--){
                    res.add(matrix[i][left_bound]);
                }
                left_bound++;
            }
        }
        return res;
    }
}

20. 力扣59 螺旋矩阵II

https://leetcode.cn/problems/spiral-matrix-ii/

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] res = new int[n][n];
        int left = 0;
        int right = n - 1;
        int top = 0;
        int bottom = n - 1;
        
        int curr = 1;
        int i = 0;
        int j = -1;
        while(curr <= n * n){
            if(i == top){
                while(j < right){
                    j++;
                    res[i][j] = curr;
                    curr++;
                }
                top++;
            }
            if(j == right){
                while(i < bottom){
                    i++;
                    res[i][j] = curr;
                    curr++;
                }
                right--;
            }
            if(i == bottom){
                while(j > left){
                    j--;
                    res[i][j] = curr;
                    curr++;
                }
                bottom--;
            }
            if(j == left){
                while(i > top){
                    i--;
                    res[i][j] = curr;
                    curr++;
                }
                left++;
            }
        }
        return res;
    }
}

21. 力扣61 旋转链表

https://leetcode.cn/problems/rotate-list/

思路:

    链表在特定位置的断开、重连。

class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if(head == null){
            return null;
        }
        ListNode countNode = head;
        int count = 0;
        while(countNode != null){
            count++;
            countNode = countNode.next;
        }
        int step = k % count;
        ListNode p1 = head;
        ListNode p2 = head;
        for(int i = 0; i < step; i++){
            p2 = p2.next;
        }
        while(p2.next != null){
            p1 = p1.next;
            p2 = p2.next;
        }
        p2.next = head;
        head = p1.next;
        p1.next = null;
        return head;
    }
}

22. 力扣62 不同路径

https://leetcode.cn/problems/unique-paths/

思路:

    基础的动态规划。

class Solution {
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];
        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(i == 0 || j == 0){
                    dp[i][j] = 1;
                } else{
                    dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
                }
            }
        }
        return dp[m - 1][n - 1];
    }
}

23. 力扣70 爬楼梯

https://leetcode.cn/problems/climbing-stairs/

class Solution {
    public int climbStairs(int n) {
        int[] dp = new int[n];
        for(int i = 0; i < n; i++){
            if(i == 0){
                dp[i] = 1;
            } else if(i == 1){
                dp[i] = 2;
            } else{
                dp[i] = dp[i - 1] + dp[i - 2];
            }
        }
        return dp[n - 1];
    }
}

24. 力扣78 子集

https://leetcode.cn/problems/subsets/

class Solution {
    List<List<Integer>> res;
    List<Integer> track;

    public List<List<Integer>> subsets(int[] nums) {
        res = new LinkedList();
        track = new LinkedList();
        backtrack(nums, 0);
        return res;
    }

    public void backtrack(int[] nums, int start){
        res.add(new LinkedList(track));
        for(int i = start; i < nums.length; i++){
            track.add(nums[i]);
            backtrack(nums, i + 1);
            track.remove(track.size() - 1);
        }
    } 
}

25. 力扣88 合并两个有序数组

https://leetcode.cn/problems/merge-sorted-array/

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int p1 = m - 1;
        int p2 = n - 1;
        int curr = m + n - 1;
        while(curr >= 0){
            if(p1 < 0){
                nums1[curr] = nums2[p2];
                p2--;
                curr--;
                continue;
            }
            if(p2 < 0){
                nums1[curr] = nums1[p1];
                p1--;
                curr--;
                continue;
            }
            if(nums1[p1] >= nums2[p2]){
                nums1[curr] = nums1[p1];
                p1--;
            } else{
                nums1[curr] = nums2[p2];
                p2--;
            }
            curr--;
        }
    }
}

26. 力扣89 格雷编码

https://leetcode.cn/problems/gray-code/

思路:

    没有思路,背公式。

class Solution {
    public List<Integer> grayCode(int n) {
        // 第i位格雷码:i / 2 ^ i
        int pro = 1;
        for(int i = 0; i < n; i++){
            pro *= 2;
        }
        List<Integer> res = new LinkedList();
        for(int i = 0; i < pro; i++){
            res.add(i / 2 ^ i);
        }
        return res;
    }
}

27. 力扣104 二叉树的最大深度

https://leetcode.cn/problems/maximum-depth-of-binary-tree/

class Solution {
    public int maxDepth(TreeNode root){
        if(root == null){
            return 0;
        }
        return Math.max(maxDepth(root.left), maxDepth(root.right)) + 1;
    }
}

28. 力扣121 买卖股票的最佳时机

https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/

思路:

    买卖股票的一系列题目都可以使用有限状态机来求解,对这道题来说有点小题大做。

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int[] dp = new int[2];
        // 0: 不持有, 1: 持有
        dp[0] = 0;
        dp[1] = -prices[0];
        for(int i = 1; i < n; i++){
            dp[0] = Math.max(dp[0], dp[1] + prices[i]);
            // 只许买一次, 所以是-prices[i]而不是dp[0]-prices[i]
            dp[1] = Math.max(dp[1], -prices[i]);
        }
        return dp[0];
    }
}

29. 力扣122 买卖股票的最佳时机II

https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int[] dp = new int[2];
        dp[0] = 0;
        dp[1] = - prices[0];
        for (int i = 1; i < n; i++) {
            dp[0] = Math.max(dp[0], dp[1] + prices[i]);
            dp[1] = Math.max(dp[1], dp[0] - prices[i]);
        }
        return dp[0];
    }
}

30. 力扣124 二叉树中的最大路径和

https://leetcode.cn/problems/binary-tree-maximum-path-sum/

思路:

    遍历二叉树时,对每一个结点要做两件事:

    1. 计算以该结点为路径的一个端点的最大路径和,供其父结点进行计算。

    2. 计算以该结点为根结点的最大路径和,做全局比较。

    比较以每个结点为根结点的最大路径和,得到全局最大路径和。

class Solution {
    int res;

    public int maxPathSum(TreeNode root) {
        res = Integer.MIN_VALUE;
        getMaxPathSum(root);
        return res;
    }

    public int getMaxPathSum(TreeNode root){
        if(root == null){
            return 0;
        }
        int curr = root.val;
        int left = getMaxPathSum(root.left);
        int right = getMaxPathSum(root.right);
        int maxPath = Math.max(Math.max(left, right), 0) + curr;
        int currMax = Math.max(curr + left + right, maxPath);
        if(currMax > res){
            res = currMax;
        }
        return maxPath;
    }
}

31. 力扣136 只出现一次的数字

https://leetcode.cn/problems/single-number/

思路:

    一个数字与0做异或操作,得到它本身,与本身做异或操作,得0。

class Solution {
    public int singleNumber(int[] nums) {
        int res = 0;
        for(int i : nums){
            res ^= i;
        }
        return res;
    }
}

32. 力扣141 环形链表

https://leetcode.cn/problems/linked-list-cycle/

class Solution {
    public boolean hasCycle(ListNode head) {
        if(head == null || head.next == null){
            return false;
        }
        ListNode p1 = head;
        ListNode p2 = head;
        while(p1 != null && p1.next != null){
            p1 = p1.next.next;
            p2 = p2.next;
            if(p1 == p2){
                return true;
            }
        }
        return false;
    }
}

33. 力扣142 环形链表II

https://leetcode.cn/problems/linked-list-cycle-ii/

思路:

    这里是使用哈希表解答。

    官方题解有另一种很巧妙的方法,使用快慢指针,两指针相遇时,从相遇点和起点各启动一个新的指针,两个新指针相遇的点就是进入环形链表的点。

public class Solution {
    public ListNode detectCycle(ListNode head) {
        Set<ListNode> memo = new HashSet();
        while(head != null){
            if(memo.contains(head)){
                return head;
            }
            memo.add(head);
            head = head.next;
        }
        return null;
    }
}

34. 力扣146 LRU缓存

https://leetcode.cn/problems/lru-cache/

思路:

    使用哈希表+双向链表。

class ListNode{
    int key;
    int val;
    ListNode pre;
    ListNode next;
    public ListNode(int key, int val){
        this.key = key;
        this.val = val;
    }
}

class LRUCache {
    int capacity;
    Map<Integer, ListNode> map = new HashMap();
    ListNode head = new ListNode(0, 0);
    ListNode tail = new ListNode(0, 0);

    public LRUCache(int capacity) {
        this.capacity = capacity;
        head.next = tail;
        tail.pre = head;
    }
    
    public int get(int key) {
        if(map.containsKey(key)){
            ListNode node = map.get(key);
            moveToFirst(node);
            return node.val;
        }
        return -1;
    }
    
    public void put(int key, int value) {
        if(map.containsKey(key)){
            ListNode node = map.get(key);
            node.val = value;
            moveToFirst(node);
        } else{
            if(map.size() == capacity){
                deleteLast();
            }
            ListNode newNode = new ListNode(key, value);
            ListNode temp = head.next;
            head.next = newNode;
            newNode.pre = head;
            newNode.next = temp;
            temp.pre = newNode;
            map.put(newNode.key, newNode);
        }
    }

    public void deleteLast(){
        ListNode last = tail.pre;
        last.pre.next = tail;
        tail.pre = last.pre;
        map.remove(last.key);
    }

    public void moveToFirst(ListNode node){
        node.pre.next = node.next;
        node.next.pre = node.pre;
        ListNode temp = head.next;
        head.next = node;
        node.pre = head;
        node.next = temp;
        temp.pre = node;
    }
}

35. 力扣148 排序链表

https://leetcode.cn/problems/sort-list/

思路:

    将链表分割成n个升序链表,依次合并。

class Solution {
    public ListNode sortList(ListNode head) {
        Queue<ListNode> queue = new LinkedList();
        queue.offer(head);
        ListNode pre = new ListNode(Integer.MIN_VALUE, head);
        while(head != null){
            if(head.val < pre.val){
                queue.offer(head);
                pre.next = null;
            }
            pre = head;
            head = head.next;
        }
        while(!queue.isEmpty()){
            ListNode node1 = queue.poll();
            if(queue.isEmpty()){
                return node1;
            } else{
                ListNode node2 = queue.poll();
                queue.offer(mergeTwoLists(node1, node2));
            }
        }
        return null;
    }

    public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
        ListNode dummy = new ListNode(-1);
        ListNode curr = dummy;
        while(list1 != null && list2 != null){
            if(list1.val <= list2.val){
                curr.next = list1;
                list1 = list1.next;
            } else{
                curr.next = list2;
                list2 = list2.next;
            }
            curr = curr.next;
        }
        if(list1 != null){
            curr.next = list1;
        }
        if(list2 != null){
            curr.next = list2;
        }
        return dummy.next;
    }
}

36. 力扣155 最小栈

https://leetcode.cn/problems/min-stack/

思路:

    维护两个栈,一个记录真实数值,另一个记录最小值。

class MinStack {
    Stack<Integer> stack;
    Stack<Integer> minStack;

    public MinStack() {
        stack = new Stack();
        minStack = new Stack();
    }
    
    public void push(int val) {
        stack.push(val);
        minStack.push(minStack.isEmpty() ? val : Math.min(val, minStack.peek()));
    }
    
    public void pop() {
        stack.pop();
        minStack.pop();
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int getMin() {
        return minStack.peek();
    }
}

37. 力扣160 相交链表

https://leetcode.cn/problems/intersection-of-two-linked-lists/

思路:

    使用两个指针分别从两个链表的头部出发,当指针走到链表尾部时,移到另一个链表的头部,两指针相遇点即链表交点。

class Solution {
    public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
        ListNode p1 = headA;
        ListNode p2 = headB;
        while(p1 != p2){
            if(p1 != null){
                p1 = p1.next;
            } else{
                p1 = headB;
            }
            if(p2 != null){
                p2 = p2.next;
            } else{
                p2 = headA;
            }
        }
        return p1;
    }
}

38. 力扣169 多数元素

https://leetcode.cn/problems/majority-element/

class Solution {
    public int majorityElement(int[] nums) {
        int n = nums.length;
        Map<Integer, Integer> memo = new HashMap();
        for(int i = 0; i < n; i++){
            memo.put(nums[i], memo.getOrDefault(nums[i], 0) + 1);
            if(memo.get(nums[i]) > n / 2){
                return nums[i];
            }
        }
        return -1;
    }
}

39. 力扣206 反转链表

https://leetcode.cn/problems/reverse-linked-list/

class Solution {
    public ListNode reverseList(ListNode head) {
        if(head == null || head.next == null){
            return head;
        }
        ListNode node = reverseList(head.next);
        head.next.next = head;
        head.next = null;
        return node;
    }
}

40. 力扣215 数组中的第K个最大元素

https://leetcode.cn/problems/kth-largest-element-in-an-array/

思路:

    没有梦想,用的人家的轮子。

class Solution {
    public int findKthLargest(int[] nums, int k) {
        int n = nums.length;
        PriorityQueue<Integer> minHeap = new PriorityQueue();
        for(int i = 0; i < n; i++){
            minHeap.offer(nums[i]);
            if(minHeap.size() > k){
                minHeap.poll();
            }
        }
        return minHeap.poll();
    }
}

41. 力扣217 存在重复元素

https://leetcode.cn/problems/contains-duplicate/

class Solution {
    public boolean containsDuplicate(int[] nums) {
        Set<Integer> set = new HashSet();
        for(int i : nums){
            if(set.contains(i)){
                return true;
            }
            set.add(i);
        }
        return false;
    }
}

42. 力扣230 二叉搜索树中第K小的元素

https://leetcode.cn/problems/kth-smallest-element-in-a-bst/

思路:

    深度优先遍历,在中序位置计数。

class Solution {
    int count = 0;
    int res = 0;

    public int kthSmallest(TreeNode root, int k) {
        traverse(root, k);
        return res;
    }

    public void traverse(TreeNode root, int k){
        if(root == null){
            return;
        }
        traverse(root.left, k);
        count++;
        if(count == k){
            res = root.val;
        }
        traverse(root.right, k);
    }
}

43. 力扣231 2的幂

https://leetcode.cn/problems/power-of-two/

思路:

    位运算,2的幂只有一位是1,其他位都是0,2的幂减一的每个位都是1,且比2的幂少一位,两者做与运算得0。

class Solution {
    public boolean isPowerOfTwo(int n) {
        return n > 0 && (n & (n - 1)) == 0;
    }
}

44. 力扣235 二叉搜索树的最近公共祖先

https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-search-tree/

思路:

    公共祖先比一个结点的值大,比另一个结点的值小,或者就是两个结点之一。从根结点向下遍历即可。

class Solution {
    TreeNode mark;

    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        traverse(root, p.val, q.val);
        return mark;
    }

    public void traverse(TreeNode root, int p, int q){
        if(root == null){
            return;
        }
        if(p < root.val && q < root.val){
            traverse(root.left, p, q);
        } else if(p > root.val && q > root.val){
            traverse(root.right, p, q);
        } else{
            mark = root;
        }
    }
}

45. 力扣236 二叉树的最近公共祖先

https://leetcode.cn/problems/lowest-common-ancestor-of-a-binary-tree/

思路:

    对每个结点来说,在其左子树上找p或q,然后再在其右子树上找p或q,如果在一棵子树上找到了p,在另一棵子树上找到了q,说明该结点是最近公共祖先。如果在同一棵子树上找到了p和q,说明该结点是公共祖先,但不是最近的,再去判断找到p和q的子树的根结点是否是最近公共祖先。

class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        return traverse(root, p, q);
    }

    public TreeNode traverse(TreeNode root, TreeNode p, TreeNode q){
        if(root == null){
            return root;
        }
        if(root == p || root == q){
            return root;
        }
        TreeNode left = traverse(root.left, p, q);
        TreeNode right = traverse(root.right, p, q);
        if(left != null && right != null){
            return root;
        } else{
            return left != null ? left : right;
        }
    }
}

46. 力扣237 删除链表中的结点

https://leetcode.cn/problems/delete-node-in-a-linked-list/

思路:

    官方题解不讲武德,是在下输了。

class Solution {
    public void deleteNode(ListNode node) {
        node.val = node.next.val;
        node.next = node.next.next;
    }
}

47. 力扣238 除自身以外数组的乘积

https://leetcode.cn/problems/product-of-array-except-self/

思路:

    正序计算累乘积数组,再倒序计算累乘积数组,结果数组的每个元素一定是两个累乘积数组中的元素的乘积。

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int n = nums.length;
        int[] arr1 = new int[n + 1];
        int[] arr2 = new int[n + 1];
        arr1[0] = 1;
        for(int i = 1; i < n + 1; i++){
            arr1[i] = arr1[i - 1] * nums[i - 1];
        }
        arr2[n] = 1;
        for(int j = n - 1; j >= 0; j--){
            arr2[j] = arr2[j + 1] * nums[j];
        }
        int[] answer = new int[n];
        for(int k = 0; k < n; k++){
            answer[k] = arr1[k] * arr2[k + 1];
        }
        return answer;
    }
}

48. 力扣292 Nim游戏

https://leetcode.cn/problems/nim-game/

class Solution {
    public boolean canWinNim(int n) {
        return n % 4 != 0;
    }
}

49. 力扣344 反转字符串

https://leetcode.cn/problems/reverse-string/

class Solution {
    public void reverseString(char[] s) {
        int n = s.length;
        int mid = n / 2;
        for(int i = 0; i <= mid - 1; i++){
            swap(s, i, n - i - 1);
        }
    }

    public void swap(char[] s, int a, int b){
        char temp = s[a];
        s[a] = s[b];
        s[b] = temp;
    }
}

50. 力扣557 反转字符串中的单词III

https://leetcode.cn/problems/reverse-words-in-a-string-iii/

class Solution {
    public String reverseWords(String s) {
        String[] ss = s.split(" ");
        int n = ss.length;
        for(int i = 0; i < n; i++){
            ss[i] = reverseString(ss[i]);
        }
        StringBuilder sb = new StringBuilder();
        for(int i = 0; i < n; i++){
            if(i != 0){
                sb.append(" ");
            }
            sb.append(ss[i]);
        }
        return sb.toString();
    }

    public String reverseString(String s) {
        char[] cs = s.toCharArray();
        int n = cs.length;
        int mid = n / 2;
        for(int i = 0; i <= mid - 1; i++){
            swap(cs, i, n - i - 1);
        }
        return new String(cs);
    }

    public void swap(char[] cs, int a, int b){
        char temp = cs[a];
        cs[a] = cs[b];
        cs[b] = temp;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值