【每日三题】分隔链表、回文链表

275 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情 >>


每日三刷,剑指千题

计划简介:

  • 每日三题,以中等题为主,简单题为辅进行搭配。保证质量题1道,数量题3道。
  • 每日早通勤在LeetCode手机端选题,思考思路,没答案的直接看题解。
  • 每日中午进行编码,时间控制在一小时之内。
  • 下班前半小时进行整理总结,并发布到掘金每日更文活动。

说明:

  • 基于以前的刷题基础,本次计划以中等题为主,大部分中等题都可以拆分为多个简单题,所以数量保证3,质量保证一道中等题即可。
  • 刷题顺序按照先刷链表、二叉树、栈、堆、队列等基本数据结构,再刷递归、二分法、排序、双指针等基础算法,最后是动态规划、贪心、回溯、搜索等复杂算法。
  • 刷题过程中整理相似题型,刷题模板。
  • 目前进度 117/1000

[剑指 Offer II 025]链表中的两数相加

给定两个 非空链表 l1l2 来代表两个非负整数。数字最高位位于链表开始位置。它们的每个节点只存储一位数字。将这两数相加会返回一个新的链表。

可以假设除了数字 0 之外,这两个数字都不会以零开头。

示例1:

img

输入:l1 = [7,2,4,3], l2 = [5,6,4]
输出:[7,8,0,7]

解析

总感觉这个题出的很蠢,其实就是想考反转链表,又套了一个看起来和算法无关的重壳子。

LeetCode 也有很多凑数题,水题,需要我们有一双慧眼。

Code

class Solution {
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        Deque<Integer>stack1=new LinkedList<>();
        Deque<Integer>stack2=new LinkedList<>();
        while (l1!=null){
            stack1.push(l1.val);
            l1=l1.next;
        }
        while (l2!=null){
            stack2.push(l2.val);
            l2=l2.next;
        }
        ListNode newHead=new ListNode(-1);
        int add=0;
        while (!stack1.isEmpty()||!stack2.isEmpty()||add!=0){
            int sum=add;
            sum+=stack1.isEmpty()?0:stack1.poll();
            sum+=stack2.isEmpty()?0:stack2.poll();
            add=sum/10;
            ListNode cur=new ListNode(sum%10);
            cur.next=newHead.next;
            newHead.next=cur;
        }
        return newHead.next;
    }
}
​

[725]分隔链表

给你一个头结点为 head 的单链表和一个整数 k ,请你设计一个算法将链表分隔为 k 个连续的部分。

每部分的长度应该尽可能的相等:任意两部分的长度差距不能超过 1 。这可能会导致有些部分为 null 。

k 个部分应该按照在链表中出现的顺序排列,并且排在前面的部分的长度应该大于或等于排在后面的长度。

返回一个由上述 k 部分组成的数组。

示例 1:

img

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

解析

这题全是逻辑,没有算法。分情况讨论了:

  • k比长度还大的,那必然是每个元素一组,剩下用 null 补上。
  • K比长度小,但恰好可以平分的,这个也简单。
  • K比长度小,又不能整除的,麻烦了。比如长度为5,分成3份,商是1,余2,剩下的两个怎么处理呢?注意看一句话,任意两部分的长度差距不能超过 1 。,所以应该分给每一部分1个,就是 2,2,1的分布。

Code

class Solution {
        public ListNode[] splitListToParts(ListNode head, int k) {
            ListNode[] ans = new ListNode[k];
            ListNode index = head;
            int size = 0;
            while (head != null) {
                size++;
                head = head.next;
            }
            int part = size / k;
            int extra = size % k;
            if (part < 1) {
                for (int i = 0; i < k; i++) {
                    if (index == null) {
                        ans[i] = null;
                    } else {
                        ListNode temp = index;
                        index = index.next;
                        temp.next = null;
                        ans[i] = temp;
                    }
​
                }
            } else {
                for (int i = 0; i < k; i++) {
                    int range = 1;
                    int partOne = part;
                    partOne = extra > 0 ? partOne + 1 : partOne;
                    ListNode temp = index;
                    while (range < partOne) {
                        index = index.next;
                        range++;
                    }
                    ListNode t = index;
                    index = index.next;
                    t.next = null;
                    ans[i] = temp;
                    extra--;
                }
            }
            return ans;
        }
    }

[面试题 02.06]回文链表

编写一个函数,检查输入的链表是否是回文的。

示例 1:

输入: 1->2
输出: false 

解析

这题用翻转链表就是个坑,代码量太大,简单的方法就是用栈。

Code

class Solution {
    public boolean isPalindrome(ListNode head) {
        Stack stack = new Stack<Integer>();
        ListNode cur = head;
        while(cur!=null){
            stack.push(cur.val);
            cur = cur.next;
        }
        while(head!=null){
            if(head.val!=(Integer)stack.pop()){
                return false;
            }
            head = head.next;
        }
        return true;
    }
}

\