leetcode 随笔17

再更新

文章目录

7.28

模拟笔试题1 – 能否被子字符串构成?

给定一个非空的字符串,判断它是否可以由它的一个子串重复多次构成。给定的字符串只含有小写英文字母,并且长度不超过10000。

因为问的是子串是否可以构成原字符串,所以子串的最大长度是原来长度的一半。最开始想错了,认为满足条件的子串的长度只能是偶数,所以没跑过。但其实也有可能是奇数。所以每次都尝试看看能不能构成原字符串。(length --)

class Solution {
    public boolean repeatedSubstringPattern(String s) {
        if(s == null || s.length() == 0){
            return false;
        }

        int length = s.length() / 2;
        while(length > 0){
            String temp = s.substring(0, length);
            int len = 0;
            int index = s.indexOf(temp);
            while(index != -1){
                index = s.indexOf(temp, index + length);
                len += length;
            }
            if(len == s.length()){
                return true;
            }
            length--;
        }
        return false;
    }
}

模拟笔试题2 – 数组旋转

给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

先整体翻转,以k位置为分割位,分别翻转前后的数组序列。

其中需要注意的是要先对输入的k进行处理,以防止输入的k大于数组的长度。

class Solution {
    public void rotate(int[] nums, int k) {
        if(nums.length == 0 || k <= 0){
            return ;
        }
        int n = k % nums.length;
        reverse(nums, 0, nums.length - 1);
        reverse(nums, 0, n - 1);
        reverse(nums, n, nums.length - 1);
    }

    public void reverse(int[] nums, int begin, int end){
        while(begin < end){
            int temp = nums[begin];
            nums[begin] = nums[end];
            nums[end] = temp;
            begin++;
            end--;
        }
    }
}

模拟笔试题3 – 最长的交叉路径(1372. 二叉树中的最长交错路径

难度中等

最开始以为是父节点需要用到子节点的信息,新建了一个内部类来返回内部信息。不过发现那样的做法有问题。(其实应该是我返回信息不完整)

这个题一眼看上去就是深度遍历的问题,不过好好思考了一下,可以用一个数组来返回信息。就像打家劫舍系列的第三题(还是第四题?)。在这个题中dfs会返回一个数组(长度为2),其中0表示左树的交叉最大长度,1表示右树的交叉最大长度。在每次返回的时候都尝试去更新maxPath,最后得到的maxPath就是我们的答案。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int maxPath = 0;

    public int longestZigZag(TreeNode root) {
        dfs(root);
        return maxPath;
    }

    public int[] dfs(TreeNode root){
        if(root == null){
            return new int[]{-1, -1};
        }
        
        //0表示左树的交叉最大长度,1表示右树的交叉最大长度
        int[] ans = new int[2];
        int[] left = dfs(root.left);
        int[] right = dfs(root.right);
        
        ans[0] = 1 + left[1];
        ans[1] = 1 + right[0];
        maxPath = Math.max(maxPath, Math.max(ans[0], ans[1]));
        return ans;
    }

}

128. 最长连续序列

难度困难

因为是未排序,所以最开始没什么思路。看了题解之后发现可以用set来做。因为原数组本来就是无序的集合。先把元素加入到set中,之后再考虑以某个数字作为连续序列开头的情况(也只有这种情况才由可能得到最长的序列)。

class Solution {
    public int longestConsecutive(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for(int num : nums){
            set.add(num);
        }
        int maxLen = 0;
        for(int num : nums){
            if(!set.contains(num - 1)){//只考虑从某个数字为开头
                int curNum = num;
                int curLen = 1;
                while(set.contains(curNum + 1)){
                    curNum++;
                    curLen++;
                }
                maxLen = Math.max(maxLen, curLen);
            }
        }
        return maxLen;
    }
}

1169. 查询无效交易

难度中等

主要是需要一个内部来来对交易进行初始化及放置。

其实用一个双重循环就能解决,不要把问题想得太过复杂。

class Solution {
    public List<String> invalidTransactions(String[] transactions) {
        Transaction[] trans = new Transaction[transactions.length];
        int index = 0;
        for(String tran : transactions){
            String[] strings = tran.split(",");
            trans[index++] = new Transaction(strings[0],Integer.parseInt(strings[1]),Integer.parseInt(strings[2]),strings[3]);
        }
        List<String> list = new ArrayList<>();
        for(int i = 0;i < trans.length;i++){
            if(trans[i].money > 1000)list.add(transactions[i]);
            else{
                for(int j = 0;j < trans.length;j++){
                    if(i != j && trans[j].name.equals(trans[i].name) && 
                    !trans[j].city.equals(trans[i].city) && 
                    Math.abs(trans[j].time - trans[i].time) <= 60){
                        list.add(transactions[i]);
                        break;
                    }
                }
            }
        }

        return list;
    }
}
class Transaction{
    String name;
    Integer time;
    Integer money;
    String city;

    public Transaction(String name, Integer time, Integer money, String city) {
        this.name = name;
        this.time = time;
        this.money = money;
        this.city = city;
    }
}

7.29

23. 合并K个排序链表

难度困难

想不到一次遍历全部的解法,按照自己的想法写了实现。还是把两个链表相加,直到包全部链表都相加了。但是这样的复杂度可能会偏高。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        ListNode head = null;
        for(int i = 0;i < lists.length;i++){
            head = mergeLists(lists[i], head);
        }
        return head;
    }


    public ListNode mergeLists(ListNode l1, ListNode l2){
        if(l1 == null){
            return l2;
        }
        if(l2 == null){
            return l1;
        }
        ListNode dummy = new ListNode();
        ListNode node = dummy;
        while(l1 != null && l2 != null){
            int value1 = l1.val;
            int value2 = l2.val;

            if(value1 < value2){
                node.next = new ListNode(value1);
                l1 = l1.next;       
            }else{
                node.next = new ListNode(value2);
                l2 = l2.next;  
            }
            node = node.next;
                 
              
        }
        if(l1 != null){
            node.next = l1;
        }else if(l2 != null){
            node.next = l2;
        }

        return dummy.next;
    }
}

看了题解,发现比较快速的解法是利用优先队列来做的。利用优先队列可以对目前的节点的值进行排序,小的值会被优先弹出。我最开始考虑的使用一个TreeMap来做,但是想了一下不太行。看来对各种数据结构还是不太熟悉。

class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        Queue<ListNode> pq = new PriorityQueue<>((v1, v2) -> v1.val - v2.val);//值小的会放在前面,并优先弹出
        for (ListNode node: lists) {
            if (node != null) {
                pq.offer(node);
            }
        }

        ListNode dummyHead = new ListNode(0);
        ListNode tail = dummyHead;
        while (!pq.isEmpty()) {
            ListNode minNode = pq.poll();
            tail.next = minNode;
            tail = minNode;
            if (minNode.next != null) {
                pq.offer(minNode.next);
            }
        }

        return dummyHead.next;
    }
}

31. 下一个排列

难度中等

这个题最开始想简单了,以为要找到从前往后找到递减序列结束的值。所以实际上并没有那么简单。

看了题解才做出来。主要想法是从后往前遍历,找到递增序列结束的位置。之后再把这个值与其后第一个大于它的值进行交换(从后往前)。最后再翻转后面的数组就能得到下一个最小排列。

public class Solution {
    public void nextPermutation(int[] nums) {
        int i = nums.length - 2;
        while (i >= 0 && nums[i + 1] <= nums[i]) {
            i--;
        }//从末尾开始,找到不满足递增的下标

        if (i >= 0) {//如果有满足条件的索引,如果不满足的话就翻转整个数组
            int j = nums.length - 1;
            while (j >= 0 && nums[j] <= nums[i]) { // 找到比nums[i]更大的一个数,并交换位置
                j--;
            }
            swap(nums, i, j);
        }

        //翻转后面的顺序
        reverse(nums, i + 1);
    }

    private void reverse(int[] nums, int start) {
        int i = start, j = nums.length - 1;
        while (i < j) {
            swap(nums, i, j);
            i++;
            j--;
        }
    }

    private void swap(int[] nums, int i, int j) {
        int temp = nums[i];
        nums[i] = nums[j];
        nums[j] = temp;
    }
}

33. 搜索旋转排序数组

难度中等

这个题感觉不难,主要还是逻辑没理清楚。

class Solution {
    public int search(int[] nums, int target) {
        int lo = 0, hi = nums.length - 1, mid = 0;
        while (lo <= hi) {
            mid = lo + (hi - lo) / 2;
            if (nums[mid] == target) {
                return mid;
            }
            // 先根据 nums[mid] 与 nums[lo] 的关系判断 mid 是在左段还是右段 
            if (nums[mid] >= nums[lo]) {//前面有序
                if (target >= nums[lo] && target < nums[mid]) {//target在不在有序的序列中
                    hi = mid - 1;
                } else {
                    lo = mid + 1;
                }
            } else {//前面无序,也就是后面有序
                if (target > nums[mid] && target <= nums[hi]) {//target在不在有序的序列中
                    lo = mid + 1;
                } else {
                    hi = mid - 1;
                }
            }
        }
        return -1;
    }

}

48. 旋转图像

难度中等

前段时间才做过,但是现在做又有点理不清逻辑了,还是要多做题啊。

j表示偏移量,i表示现在在旋转的层数

class Solution {
    public void rotate(int[][] matrix) {
        int n = matrix.length;
        
        for(int i = 0;i < n / 2;i++){
            for(int j = i;j < n - i - 1;j++){
                int temp = matrix[i][j];
                matrix[i][j] = matrix[n - j - 1][i];
                matrix[n - j - 1][i] = matrix[n - 1 - i][n - j - 1];
                matrix[n - 1 - i][n - j - 1]=matrix[j][n - 1 - i];
                matrix[j][n - 1 - i]=temp;
            }
        }
    }
}

7.30

343. 整数拆分

难度中等

这个题通过举了几个例子,发现在n大于4的情况下应该要尽可能把数字拆分了拥有更多个3。但是有一个特殊情况,就是当最后是4时,这时不应该再次拆分,而就应该用4来表示。

class Solution {
    public int integerBreak(int n) {
        if(n == 2){
            return 1;
        }else if(n == 3){
            return 2;
        }else if(n == 4){
            return 4;
        }
        int count = n / 3;
        int num = n % 3;
        if(num == 1 && count > 1){
            count--;
            num += 3;
        }

        if(num != 0){
            return (int)Math.pow(3, count) * num;
        }else{
            return (int)Math.pow(3, count);
        }
        
    }
}

617. 合并二叉树

难度简单

就是一个简单的递归就可以解决。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode mergeTrees(TreeNode t1, TreeNode t2) {
        if(t1 == null){
            return t2;
        }
        if(t2 == null){
            return t1;
        }

        TreeNode root = new TreeNode(t1.val + t2.val);
        root.left = mergeTrees(t1.left, t2.left);
        root.right = mergeTrees(t1.right, t2.right);

        return root;
    }
}

8.1

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

难度中等

之前已经做过类似的题目了

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
        if(root == null || root == p || root == q){
            return root;
        }
        TreeNode l = lowestCommonAncestor(root.left, p, q);
        TreeNode r = lowestCommonAncestor(root.right, p, q);
        if(l != null && r != null){
            return root;
        }else if(l == null){
            return r;
        }else{
            return l;
        }
    }
}

283. 移动零

难度简单

我的想法是先记录下0的数量,再把所有的0放在连续的地方,之后把后面的元素赋给0的序列中。最后再把数组后面对应的0的数量的地方置为0。

class Solution {
    public void moveZeroes(int[] nums) {
        int count = 0;
        for(int num : nums){
            if(num == 0){
                count ++;
            }
        }

        int begin = 0;
        int end = 0;
        int len = nums.length;
        //把0都放在连续的地方
        while(begin < len && end < len){
            while(begin < len && nums[begin] != 0){
                begin++;
            }

            while(end < len && nums[end] == 0){
                end++;
            }
            
            if(begin > end){
                end++;
                continue;
            }

            if(begin < len && end < len){
                swap(nums, begin, end);
                begin++;
                end++;
            }
        }

        for(int i = begin + count;i < len;i++){
            swap(nums, begin, i);
            begin++;
        }

        if(begin + count < len){
            for(int i = 1;i <= count;i++){
                nums[len - i] = 0;
            }
        }
    }

    public void swap(int[] arr, int i, int j){
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }
}

看了题解发现有更简单的做法。我们只需要将所有非0的值都先放到数组的前面,之后再把之后的序列全部置为0就可以了。

class Solution {
    public void moveZeroes(int[] nums) {
        int j = 0;
        for(int i = 0;i < nums.length;i++){
            if(nums[i] != 0){
                nums[j++] = nums[i];
            }
        }
        for(int i = j;i < nums.length;i++){
            nums[i] = 0;
        }
    }
}

8.2

58. 最后一个单词的长度

难度简单

先转变成数组,返回最后一个字符串的长度即可。不过需要注意可能会有多个空格相邻的情况。

class Solution {
    public int lengthOfLastWord(String s) {
        String[] strs = s.split(" ");
        for(int i = strs.length - 1;i >= 0; i--){
            if(!strs[i].equals("")){
                return strs[i].length();
            }
        }
        return 0;
    }
}

或者直接从后面开始遍历,先把末尾的空格都略过,再得到最后一个字符串的长度。

class Solution {
    public int lengthOfLastWord(String s) {
        int i = s.length() - 1;
        while(i >= 0 && s.charAt(i) == ' '){
            i--;
        }
        int len = 0;
        while(i >= 0 && s.charAt(i) != ' '){
            i--;
            len++;
        }
        return len;
    }
}

53. 最大子序和

难度简单

已经做过几遍了。动态的思想。

class Solution {
    public int maxSubArray(int[] nums) {
        int sum = 0;
        int maxSum = Integer.MIN_VALUE;
        for(int num : nums){
            if(sum > 0){
                sum += num;
            }else{
                sum = num;
            }
            maxSum = Math.max(maxSum, sum);
        }
        return maxSum;
    }
}

25. K 个一组翻转链表

难度困难

nice,自己把这个题做了出来,而且还是1000%的速度,有进步。

其实也不算特别难,只是在反转链表的基础上增加了条件。我的想法是记录下每次反转链表部分的前一个和后一个节点,之后去反转这部分的链表。反转结束后再把这三部分拼接起来。其中需要注意的是遍历时node的更新规则是不一样的,反转时会对链表有影响,所以不能直接node = node.next。在做的时候这个问题还是困扰了挺久的。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode reverseKGroup(ListNode head, int k) {
        if(head == null || k == 1){
            return head;
        }
        int len = 0;
        ListNode node = head;//遍历链表的节点
        ListNode reverseHead = head;//每次反转的头部
        ListNode h = head;//初始为head,为了防止一次都不会反转的情况
        ListNode pre = null;//链表反转结束之后的最后一个节点
        ListNode next = null;//记录下遍历时链表的下一个节点

        while(len < k && node != null){
            len++;
            if(len == k){
                next = node.next;
                ListNode temp = reverseList(reverseHead, k);//反转链表之后的头结点
                if(h == head){//更新头结点
                    h = temp;
                }else{//需要把反转的节点拼接起来
                    pre.next = temp;
                }
                pre = reverseHead;

                reverseHead.next = next;//reverseHead现在已经是反转后的末尾
                reverseHead = next;
                len = 0;
                node = next;
            }else{
                node = node.next;
            }   
        }
        return h;
    }

    //反转链表
    public ListNode reverseList(ListNode head, int k){
        ListNode pre = null;//反转用的,是反转的头部
        ListNode next = null;
        ListNode node = head;
        int len = 0;
        while(len < k && node != null){
            next = node.next;
            node.next = pre;
            pre = node;
            node = next;
            len++;
        }
        return pre;
    }
}

29. 两数相除

难度中等

emmm,只会用暴力来做,不过超时了。

看了题解,发现可以用二分的思想来做。主要想法是每次都尽可能多的减去2^n的divisor。

class Solution {
    public int divide(int dividend, int divisor) {
		if(dividend == Integer.MIN_VALUE && divisor == -1)
			return Integer.MAX_VALUE;
		
		boolean k = (dividend > 0 && divisor > 0) || (dividend < 0 && divisor < 0);
		int result = 0;
		dividend = -Math.abs(dividend);
        divisor = -Math.abs(divisor);
		while(dividend <= divisor) {
			int temp = divisor;
			int c = 1;
			while(dividend - temp <= temp) {
				temp = temp << 1;
				c = c << 1;
			}
			dividend -= temp;
			result += c;
		}
		return k ? result : -result;
	}
}

44. 通配符匹配

难度困难

最开始用了回溯的做法,但是超时了。之后就没有了思路。

看了题解,发现可以用动态规划的方法来做。确实这样做的话会比较简单。

class Solution {
    public boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();
        boolean[][] dp = new boolean[m + 1][n + 1];//i、j分别表示s的i位置与p的j位置是否匹配
        dp[0][0] = true;
        for(int i = 1;i <= n;i++){//首先处理p的开头为*的情况,这种情况下不论s为什么都能匹配
            if(p.charAt(i - 1) == '*'){
                dp[0][i] = true;
            }else{
                break;
            }
        }


        for(int i = 1;i <= m;i++){
            for(int j = 1;j <= n;j++){
                if(s.charAt(i - 1) == p.charAt(j - 1) || p.charAt(j - 1) == '?'){
                    dp[i][j] = dp[i - 1][j - 1];
                }else if(p.charAt(j - 1) == '*'){
                    dp[i][j] = dp[i - 1][j] || dp[i][j - 1];
                }
            }
        }
        return dp[m][n];
    }
}

98. 验证二叉搜索树

难度中等

二叉搜索树的中序遍历序列应该是一个递增的序列。所以简单的方法就是先中序遍历得到序列,在判断序列是不是递增的。如果递增则满足要求,如果不是,则不是二叉搜索树。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public boolean isValidBST(TreeNode root) {
        List<Integer> list = new ArrayList<>();
        inorder(root, list);
        for(int i = 1;i < list.size();i++){
            if(list.get(i) <= list.get(i - 1)){
                return false;
            }
        }
        return true;
    }

    public void inorder(TreeNode root, List<Integer> list){
        if(root == null){
            return ;
        }
        inorder(root.left, list);
        list.add(root.val);
        inorder(root.right, list);
    }
}

8.6

415. 字符串相加

难度简单

主要就是位数的相加。

class Solution {
    public String addStrings(String num1, String num2) {
        if(num1.length() == 0){
            return num2;
        }

        if(num2.length() == 0){
            return num1;
        }
        StringBuilder sb = new StringBuilder();
        
        int carry = 0;
        int index1 = num1.length() - 1;
        int index2 = num2.length() - 1;

        while(index1 >= 0 || index2 >= 0 || carry > 0){
            int value1 = index1 >= 0 ? Integer.parseInt(String.valueOf(num1.charAt(index1))) : 0;
            int value2 = index2 >= 0 ? Integer.parseInt(String.valueOf(num2.charAt(index2))) : 0;

            int sum = value1 + value2 + carry;
            carry = sum / 10;
            sb.append(sum % 10);

            index1--;
            index2--;
        }

        return sb.reverse().toString();
    }
}

207. 课程表

难度中等

这个题一看就是深度遍历去找有没有环,但是自己的写法总有问题。先把自己的做法记录下来。

class Solution {
    //用图的形式表示,不能有环,如果有环则说明不能完成。没有环则说明可以完成课程表
    class Node{
        int course;
        List<Node> pres = new ArrayList<>();

        Node(int course){
            this.course = course;
        }
    }

    public boolean canFinish(int numCourses, int[][] prerequisites) {
        Map<Integer, Node> map = new HashMap<>();
        for(int i = 0;i < prerequisites.length;i++){
            int course = prerequisites[i][0];
            int pre = prerequisites[i][1];

            //先处理前续课程
            Node preNode = null;
            if(map.containsKey(pre)){
                preNode = map.get(pre);
            }else{
                preNode = new Node(pre);
                map.put(pre, preNode);
            }

            //再处理现在的课程
            Node curNode = null;
            if(map.containsKey(course)){
                curNode = map.get(course);
            }else{
                curNode = new Node(course);
                map.put(course, curNode);
            }
            curNode.pres.add(preNode);
        }

        // for(Map.Entry<Integer, Node> entry : map.entrySet()){
        //     System.out.println(entry.getKey() + ":");
        //     for(Node pre : entry.getValue().pres){
        //         System.out.print(pre.course + " ");
        //     }
        //     System.out.println();
        //     System.out.println("-----------------");
        // }

        //所有的节点都处理过了,现在去判断其中的节点有没有环。
        for(int i = 0;i < numCourses;i++){
            if(map.containsKey(i)){
                if(!dfs(map.get(i), new boolean[numCourses])){
                    return false;
                }
            }
        }
       
        return true;
    }

    public boolean dfs(Node node, boolean[] learned){
        List<Node> pres = node.pres;
        for(int i = 0;i < pres.size();i++){
            Node pre = pres.get(i);
            if(learned[pre.course]){
                return false;
            }
            learned[pre.course] = true;
            if(!dfs(pre, learned)){
                return false;
            }
        }
        return true;
    }
}

然后去看了题解,发现别人的思路就是清晰。把节点分为3个状态,根据节点的状态来判断有没有存在环。

class Solution {
    List<List<Integer>> edges;
    int[] visited;
    boolean valid = true;

    public boolean canFinish(int numCourses, int[][] prerequisites) {
        edges = new ArrayList<List<Integer>>();
        for (int i = 0; i < numCourses; ++i) {
            edges.add(new ArrayList<Integer>());
        }
        visited = new int[numCourses];
        for (int[] info : prerequisites) {
            edges.get(info[1]).add(info[0]);
        }
        for (int i = 0; i < numCourses && valid; ++i) {
            if (visited[i] == 0) {//0标识未搜索,1标识搜索中,2标识已经搜索结束
                dfs(i);
            }
        }
        return valid;
    }

    public void dfs(int u) {
        visited[u] = 1;
        for (int v: edges.get(u)) {
            if (visited[v] == 0) {
                dfs(v);
                if (!valid) {
                    return;
                }
            } else if (visited[v] == 1) {
                valid = false;
                return;
            }
        }
        visited[u] = 2;
    }
}

8.7

169. 多数元素

难度简单

最简单的就是哈希表

class Solution {
    public int majorityElement(int[] nums) {
        Map<Integer, Integer> map = new HashMap<>();
        for(int num : nums){
            if(map.containsKey(num)){
                map.put(num, map.get(num) + 1);
            }else{
                map.put(num, 1);
            }
        }
        int count = nums.length / 2;
        for(Map.Entry<Integer, Integer> entry : map.entrySet()){
            if(entry.getValue() > count){
                return entry.getKey();
            }
        }
        return -1;
    }
}

因为一定存在目标值,所以可以先排序,中位数一定是我们想要的结果。不过这样的做法改变了原有数组的顺序。

class Solution {
    public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length / 2];
    }
}

309. 最佳买卖股票时机含冷冻期

难度中等

股票问题,动态规划问题。这个题最开始觉得有三个状态没错,但是自己在划分的时候错了,所以状态转移方程一直没写出来。参照了题解才做出来。主要还是状态转移要写对。

class Solution {
    public int maxProfit(int[] prices) {
        int len = prices.length;
        if(len == 0){
            return 0;
        }
        int[][] dp = new int[len][3];//0表示持有股票,1表示不持有股票,且处于冷冻期,2表示不持有股票,也不处于冷冻期;
        dp[0][0] = -prices[0];
        for(int i = 1;i < len;i++){
            dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][2] - prices[i]);//这个股票可能是之前就持有的,也可能是今天不在冷冻期当天购买的
            dp[i][1] = dp[i - 1][0] + prices[i];//前一天进行了买入,今天处于冷冻的话,就需要卖出之前的股票
            dp[i][2] = Math.max(dp[i - 1][1], dp[i - 1][2]);//不持有股票,也不在冷冻期,说明今天没有做任何操作,现在的最大值就是之前的最大钱数。[0]当天买入股票没有意义
        }
        return Math.max(dp[len - 1][1], dp[len - 1][2]);
    }
}

226. 翻转二叉树

难度简单

递归解决

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    public TreeNode invertTree(TreeNode root) {
        if(root == null){
            return root;
        }
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
        
        invertTree(root.left);
        invertTree(root.right);
        return root;
    }
}

146. LRU缓存机制

难度中等

主要是用linkedList和map来实现的。为什么要用map,就是为了能够在O1的时间内得到对应的value。

class LRUCache {
    private LinkedList<Integer> list = new LinkedList<>();
    private Map<Integer, Integer> map = new HashMap<>();
    private int capacity;
    private int curSize = 0;
    public LRUCache(int capacity) {
        this.capacity = capacity;
    }
    
    public int get(int key) {
        if(map.containsKey(key)){
            Iterator<Integer> iter = list.iterator();
            while (iter.hasNext()) {
                int item = iter.next();
                if (item == key) {
                    iter.remove();
                }
            }
            list.add(key);
            return map.get(key);
        }else{
            return -1;
        }
    }
    
    public void put(int key, int value) {
        if(map.containsKey(key)){
            Iterator<Integer> iter = list.iterator();
            while (iter.hasNext()) {
                int item = iter.next();
                if (item == key) {
                    iter.remove();
                }
            }
            list.add(key);
            map.put(key, value);
            return ; 
        }
        
        if(curSize < capacity){
            curSize++;        
        }else{
            //满了,需要弹出一个
            map.remove(list.removeFirst());
        }
        map.put(key, value);
        list.add(key);               
    }
}

/**
 * Your LRUCache object will be instantiated and called as such:
 * LRUCache obj = new LRUCache(capacity);
 * int param_1 = obj.get(key);
 * obj.put(key,value);
 */

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

难度中等

主要思想就是用左右相乘数组。我在做的时候nums的索引用错了,所以花了好些时间去找问题。

class Solution {
    public int[] productExceptSelf(int[] nums) {
        int n = nums.length;
        if(n == 0){
            return new int[0];
        }


        int[] leftArr = new int[n];
        int[] rightArr = new int[n];
        leftArr[0] = 1;
        rightArr[n - 1] = 1;

        for(int i = 1;i < n;i++){
            leftArr[i] = nums[i - 1] * leftArr[i - 1];
        }

        for(int i = n - 2;i >= 0;i--){
            rightArr[i] = nums[i + 1] * rightArr[i + 1];
        }

        int[] ans = new int[n];
        for(int i = 0;i < n;i++){
            // System.out.println(i + ":" + leftArr[i] + "--" + rightArr[i]);
            ans[i] = leftArr[i] * rightArr[i];
        }
        return ans;
    }
}

543. 二叉树的直径

难度简单

主要是计算深度,用一个全局变量来维护得到的最大直径。

class Solution {
    int ans;
    public int diameterOfBinaryTree(TreeNode root) {
        ans = 1;
        depth(root);
        return ans - 1;
    }
    
    public int depth(TreeNode node) {
        if (node == null) 
            return 0; // 访问到空节点了,返回0
        int L = depth(node.left); // 左儿子为根的子树的深度
        int R = depth(node.right); // 右儿子为根的子树的深度
        
        ans = Math.max(ans, L + R + 1); // 计算d_node即L+R+1 并更新ans
        
        return Math.max(L, R) + 1; // 返回该节点为根的子树的深度
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值