Leetcode_分治算法

***合并K个升序链表

1 题目描述

给你一个链表数组,每个链表都已经按升序排列。

请你将所有链表合并到一个升序链表中,返回合并后的链表。

示例 1

输入:lists = [[1,4,5],[1,3,4],[2,6]]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

示例 2:

输入:lists = []
输出:[]

示例 3:

输入:lists = [[]]
输出:[]

提示:

k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10 ^ 4
lists[i] 按 升序 排列
lists[i].length 的总和不超过 10^4

2 解题(Java)

采用分治合并算法,参考树的后序遍历。

代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        if (lists.length==0) {
            return null;
        }
        return merge(lists, 0, lists.length-1);
    }
    public ListNode merge(ListNode[] lists, int left, int right) {
        if (left == right) {
            return lists[left];
        }
        int mid = (left + right) / 2;
        ListNode l1 = merge(lists, left, mid);
        ListNode l2 = merge(lists, mid+1, right);
        return mergeTwoLists(l1, l2);
    }
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        ListNode dummyHead = new ListNode();
        ListNode cur = dummyHead;
        while(l1 != null && l2 != null) {
            if (l2.val < l1.val) {
                cur.next = new ListNode(l2.val);
                l2 = l2.next;
            } else {
                cur.next = new ListNode(l1.val);
                l1 = l1.next;
            }
            cur = cur.next;
        }
        cur.next = l1 != null ? l1 : l2;
        return dummyHead.next;
    }
}

3 复杂性分析

  • 时间复杂度O(Nlogk):数组长度为k,数组中结点总数为N,树的每一层合并时间复杂度为O(N),共logk层,因此时间复杂度为O(Nlogk);
  • 空间复杂度O(N + logk):递归深度O(logk),分治归并过程需要借助最大为O(N)的链表空间;

***表达式求值

1 题目描述

请写一个整数计算器,支持加减乘三种运算和括号。

示例1

输入

“1 + 2”

返回值

3

示例2

输入

“( 2 * ( 3 - 4 ) ) * 5”

返回值

-10

示例3

输入

“3 + 2 * 3 * 4 - 1”

返回值

26

2 解题(Java)

import java.util.*;

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     * 返回表达式的值
     * @param s string字符串 待计算的表达式
     * @return int整型
     */
    public int solve (String s) {
        s = s.trim();
        Deque<Integer> stack = new LinkedList<>();
        int number = 0;
        char sign = '+';
        char[] charArray = s.toCharArray();
        for (int i=0; i<charArray.length; i++) {
            char c = charArray[i];
            if (c == ' ') {
                continue;
            }
            else if (Character.isDigit(c)) {
                number = number * 10 + c - '0';
            }
            else if (c == '(') {
                int j = i + 1;
                int counterPartition = 1;
                while (counterPartition > 0) {
                    if (charArray[j] == '(') counterPartition++;
                    else if (charArray[j] == ')') counterPartition--;
                    j++;
                }
                number = solve(s.substring(i+1, j-1));
                i = j - 1;
            }
            if (!Character.isDigit(c) || i == charArray.length - 1) {
                if (sign == '+') {
                    stack.push(number);
                } else if (sign == '-') {
                    stack.push(-1 * number);
                } else if (sign == '*') {
                    stack.push(stack.pop() * number);
                } else if (sign == '/') {
                    stack.push(stack.pop() / number);
                }
                number = 0;
                sign = c;
            }
        }
        int ans = 0;
        while (!stack.isEmpty()) {
            ans += stack.pop();
        }
        return ans;
    }
}

3 复杂性分析

  • 时间复杂度O(N):N为字符串长度,需线性遍历一遍字符串;
  • 空间复杂度O(N):N为字符串长度,栈中存储的元素数量不超过N;

排序链表***

1 题目描述

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。

进阶

  • 你可以在 O(nlogn) 时间复杂度和常数级空间复杂度下,对链表进行排序吗?

示例 1

在这里插入图片描述

输入:head = [4,2,1,3]
输出:[1,2,3,4]

示例 2

在这里插入图片描述

输入:head = [-1,5,3,4,0]
输出:[-1,0,3,4,5]

示例 3

输入:head = []
输出:[]

提示

  • 链表中节点的数目在范围 [0, 5 * 10 ^ 4] 内
  • -10 ^ 5 <= Node.val <= 10 ^ 5

2 解题(Java)

题目解析

  1. 最适合链表的排序算法是归并排序。如果采用自顶向下的递归实现,则空间复杂度为O(log n),如果要达到O(1)的空间复杂度,则需要使用自底向上的实现方式;
  2. 首先求得链表的长度length,然后将链表拆分成子链表进行合并;
  3. 用subLength表示每次需要排序的子链表的长度,初始subLength=1;
  4. 每次将链表拆分成若干个长度为subLength的子链表(最后一个子链表的长度可以小于subLength),按照每两个子链表一组进行合并,合并后即可得到若干个长度为subLength * 2的有序子链表(最后一个子链表的长度可以小于subLength * 2);
  5. 将subLength的值加倍,重复4,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于length,整个链表排序完毕;

代码

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode sortList(ListNode head) {
        int length = 0;
        ListNode node = head;
        while (node != null) {
            node = node.next;
            length++;
        }
        ListNode dummyHead = new ListNode(0, head);
        for (int subLength = 1; subLength < length; subLength *= 2) {
            ListNode prev = dummyHead, curr = dummyHead.next;
            while (curr != null) {
                ListNode head1 = curr;
                for (int i=1; i<subLength && curr.next != null; i++) {
                    curr = curr.next;
                }
                ListNode head2 = curr.next;
                curr.next = null;
                curr = head2;
                for (int i = 1; i < subLength && curr != null && curr.next != null; i++) {
                    curr = curr.next;
                }
                ListNode next = null;
                if (curr != null) {
                    next = curr.next;
                    curr.next = null;
                }
                ListNode merged = merge(head1, head2);
                prev.next = merged;
                while (prev.next != null) {
                    prev = prev.next;
                }
                curr = next;
            }
        }
        return dummyHead.next;
    }

    public ListNode merge(ListNode head1, ListNode head2) {
        ListNode dummyHead = new ListNode();
        ListNode temp = dummyHead;
        while (head1 != null && head2 != null) {
            if (head1.val <= head2.val) {
                temp.next = head1;
                head1 = head1.next;
            } else {
                temp.next = head2;
                head2 = head2.next;
            }
            temp = temp.next;
        }
        temp.next = head1 == null ? head2 : head1;
        return dummyHead.next;
    }
}

3 复杂性分析

  • 时间复杂度O(nlogn):其中 n 是链表的长度;
  • 空间复杂度O(1);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hellosc01

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值