博客记录-day158-力扣(买卖股票,归并)

128 阅读4分钟

一、力扣

1、将二叉搜索树转化为排序的双向链表

LCR 155. 将二叉搜索树转化为排序的双向链表

image.png

class Solution {
    // pre用于记录当前节点的前驱节点
    private Node pre;
    // head指向链表的头节点(即中序遍历的第一个节点)
    private Node head;

    public Node treeToDoublyList(Node root) {
        if (root == null) return null;
        // 中序遍历重构链表
        dfs(root);
        // 将链表首尾相连形成循环
        head.left = pre;   // 头节点的左指针指向尾节点
        pre.right = head;  // 尾节点的右指针指向头节点
        return head;
    }

    private void dfs(Node root) {
        if (root == null) return;
        
        dfs(root.left);  // 递归处理左子树
        
        // 处理当前节点
        if (pre == null) {
            // 第一次访问的是最左节点,作为链表头
            head = root;
        } else {
            // 将前驱节点的右指针指向当前节点,当前节点的左指针指向前驱
            pre.right = root;
            root.left = pre;
        }
        pre = root;  // 更新前驱节点为当前节点
        
        dfs(root.right);  // 递归处理右子树
    }
}

2、旋转链表

61. 旋转链表

image.png

class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        // 计算链表的长度
        int n = 0;
        for (ListNode temp = head; temp != null; temp = temp.next) {
            n++;
        }
        // 处理空链表的情况
        if (n == 0) return head;
        // 计算有效旋转次数,避免重复旋转(k大于链表长度时取模)
        k = k % n;
        // 无需旋转的情况:k为0、链表为空或只有一个节点
        if (k == 0 || head == null || head.next == null) {
            return head;
        }
        // 反转整个链表,将原尾节点变为新头节点,方便后续分割
        ListNode newHead = reverse(head);
        // 定位到分割点:pre为前k个节点的尾节点,cur为剩余部分的头节点
        ListNode cur = newHead;
        ListNode pre = null;
        for (int i = 0; i < k; i++) {
            pre = cur;
            cur = cur.next;
        }
        pre.next=null;
        ListNode firList=reverse(newHead);
        ListNode secList=reverse(cur);
        newHead.next=secList;
        return firList;
    }

    // 辅助函数:反转链表
    public ListNode reverse(ListNode head) {
        ListNode pre = null;
        while (head != null) {
            ListNode next = head.next; // 保存下一个节点
            head.next = pre;           // 当前节点指向前驱
            pre = head;                // 前驱后移
            head = next;               // 当前节点后移
        }
        return pre; // 返回反转后的头节点
    }
}

3、二叉树展开为链表

114. 二叉树展开为链表

image.png

class Solution {
    TreeNode last;
    public void flatten(TreeNode root) {
        dfs(root);
    }
    public void dfs(TreeNode root){
        if(root==null) return;
        dfs(root.right);
        dfs(root.left);
        root.left=null;
        root.right=last;
        last=root;
    }
}

4、归并排序-排序链表

148. 排序链表

image.png

class Solution {
    public ListNode sortList(ListNode head) {
        if(head==null||head.next==null) return head;
        ListNode mid=finMid(head);
        ListNode fir=sortList(head);
        ListNode sec=sortList(mid);
        return merge(fir,sec);
    }
    public ListNode finMid(ListNode head){
        ListNode fast=head;
        ListNode slow=head;
        ListNode pre=head;
        while(fast!=null&&fast.next!=null){
            fast=fast.next.next;
            pre=slow;
            slow=slow.next;
        }
        pre.next=null;
        return slow;
    }
    public ListNode merge(ListNode fir,ListNode sec){
        ListNode dummy=new ListNode(0);
        ListNode las=dummy;
        while(fir!=null&&sec!=null){
            if(fir.val>sec.val){
                las.next=sec;
                las=sec;
                sec=sec.next;
            }else{
                las.next=fir;
                las=fir;
                fir=fir.next;
            }
        }
        las.next=fir==null?sec:fir;
        return dummy.next;
    }
}

5、归并排序-交易逆序对的总数

LCR 170. 交易逆序对的总数

image.png

class Solution {
    int res;
    public int reversePairs(int[] record) {
        mergeSort(record,0,record.length-1);
        System.out.println(Arrays.toString(record));
        return res;
    }
    public void mergeSort(int[] record,int left,int right){
        if(left>=right) return;
        int mid=(left+right)/2;
        mergeSort(record,left,mid);
        mergeSort(record,mid+1,right);
        merge(record,left,mid,right);
    }
    public void merge(int[] record,int fir,int sec,int las){
        int[] temp=new int[las-fir+1];
        int cur1=fir;
        int cur2=sec+1;
        int point=0;
        while(cur1<=sec&&cur2<=las){
            if(record[cur1]>record[cur2]){
                res+=sec-cur1+1;
                temp[point++]=record[cur2++];
            }else{
                temp[point++]=record[cur1++];
            }
        }
        while(cur1<=sec){
            temp[point++]=record[cur1++];
        }
        while(cur2<=las){
            temp[point++]=record[cur2++];
        }
        for(int i=fir;i<=las;i++){
            record[i]=temp[i-fir];
        }
    }
}

6、买卖股票的最佳时机 III

123. 买卖股票的最佳时机 III

image.png

class Solution {
    public int maxProfit(int[] prices) {
        int n=prices.length;
        /*
         * 定义 5 种状态:
         * 0: 没有操作, 1: 第一次买入, 2: 第一次卖出, 3: 第二次买入, 4: 第二次卖出
         */
        int[][] dp=new int[n][5];
        dp[0][1]=-prices[0];
        dp[0][3]=-prices[0];
        for(int i=1;i<n;i++){
            dp[i][0]=dp[i-1][0];
            dp[i][1]=Math.max(dp[i-1][0]-prices[i],dp[i-1][1]);
            dp[i][2]=Math.max(dp[i-1][1]+prices[i],dp[i-1][2]);
            dp[i][3]=Math.max(dp[i-1][3],dp[i-1][2]-prices[i]);
            dp[i][4]=Math.max(dp[i-1][4],dp[i-1][3]+prices[i]);
        }
        return dp[n-1][4];
    }
}

7、买卖股票的最佳时机 IV

188. 买卖股票的最佳时机 IV

image.png

class Solution {
    public int maxProfit(int k, int[] prices) {
        int n=prices.length;
        // [天数][股票状态]
        // 股票状态: 
        //奇数表示第 k 次交易持有/买入, 偶数表示第 k 次交易不持有/卖出, 0 表示没有操作
        
        int[][] dp=new int[n][2*k+1];
        for(int i=1;i<=2*k;i+=2){
            dp[0][i]=-prices[0];
        }
        for(int i=1;i<n;i++){
            for(int j=1;j<=2*k;j++){
                if(j%2==1){
                    dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-1]-prices[i]);
                }else{
                    dp[i][j]=Math.max(dp[i-1][j],dp[i-1][j-1]+prices[i]);
                }
            }
        }
        return dp[n-1][2*k];
    }
}