zoukankan      html  css  js  c++  java
  • 链表题汇总

    c. 反转链表

    输入一个链表,反转链表后,输出新链表的表头。

    思路
    还是递归好想

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

    迭代,你指针赋值之前一定要保存下一个指针在哪,不然会找不到

    class Solution {
        public ListNode ReverseList(ListNode head) {
            if (head==null || head.next==null) return head;
            ListNode pre=null, post=head;
            while (head!=null) {
                post=head.next;
                head.next=pre;
                pre=head;
                head=post;
            }
            return pre;
        }
    }
    

    b. 链表内指定区间反转

    思路
    先找到反转区间的起点,然后双指针翻转即可
    注:第一次因为指针指向顺序的错误导致丢失了结点

    func reverseBetween(head *ListNode, m, n int) *ListNode {
        dead := new(ListNode)
        dead.Next = head
        pre, cur := dead, dead.Next //推荐这里写pre=dead代替pre=head,因为后面会因为pre为null报错
        for i := 1; i < m; i++ {
            pre = cur
            cur = cur.Next
        }
        for i := 0; i < n-m; i++ {
            nxt := cur.Next
            cur.Next = cur.Next.Next
            nxt.Next = pre.Next
            pre.Next = nxt
        }
        return dead.Next
    }
    

    a. K 个一组翻转链表

    给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。

    class Solution {
        public ListNode reverseKGroup(ListNode head, int k) {
            int n=0;
            ListNode dead=new ListNode(0), pre=dead, cur=head, p=head, tmp;
            dead.next=head;
            while (p!=null) { n++; p=p.next; }
            for (int i=0, group=n/k; i<group; i++) {
                for (int j=1; j<k; j++) {
                    tmp=cur.next;
                    cur.next=tmp.next;
                    tmp.next=pre.next; //注:不是cur,因为cur会交换到后面,此时如果pre.next始终指向后一个结点
                    pre.next=tmp;
                }
                pre=cur;
                cur=cur.next;
            }
            return dead.next;
        }
    }
    

    c. 合并有序链表

    将两个有序的链表合并为一个新链表,要求新的链表是通过拼接两个链表的节点来生成的。

    class Solution {
        public ListNode mergeTwoLists (ListNode l1, ListNode l2) {
            if (l1==null) return l2;
            if (l2==null) return l1;
            ListNode dead=new ListNode(-1), p=dead;
            dead.next=p;
            while (l1!=null && l2!=null) {
                if (l1.val<l2.val) {
                    p.next=l1;
                    l1=l1.next;
                } else {
                    p.next=l2;
                    l2=l2.next;
                }
                p=p.next;
            }
            p.next=l1==null ? l2 : l1;
            return dead.next;
        }
    }
    

    c. 两个链表的第一个公共结点

    输入两个链表,找出它们的第一个公共结点。

    简单解法

    class Solution {
        public ListNode FindFirstCommonNode(ListNode p1, ListNode p2) {
            boolean vis[]=new boolean[100005];
            while (p1!=null) {
                vis[p1.val]=true;
                p1=p1.next;
            }
            while (p2!=null) {
                if (vis[p2.val]) return p2;
                p2=p2.next;
            }
            return null;
        }
    }
    

    双指针:p走了a+b,q走了b+a,则会在c点相遇

    class Solution {
        public ListNode FindFirstCommonNode(ListNode head1, ListNode head2) {
            ListNode p1=head1, p2=head2;
            while (p1!=p2) {
                p1 = p1==null ? head2 : p1.next;
                p2 = p2==null ? head1 : p2.next;
            }
            return p1;
        }
    }
    

    c. 判断一个链表是否为回文结构

    请判断一个链表是否为回文链表

    思路:栈,需要想一下链表的结点个数的奇偶性:快慢指针找到链表的后半段,并存入栈中(链表长度为奇数的话就是中间结点的下一个),然后比较栈中元素和前半段元素

    class Solution {
        public boolean isPalindrome(ListNode head) {
            if (head==null || head.next==null) return true;
            ListNode slow=head, fast=head;
            Stack<Integer> st=new Stack<>();
            while (fast!=null && fast.next!=null) {
                slow=slow.next;
                fast=fast.next.next;
            }
            while (slow!=null) {
                st.push(slow.val);
                slow=slow.next;
            }
            while (!st.isEmpty()) {
                if (st.pop()!=head.val) return false;
                head=head.next;
            }
            return true;
        }
    }
    

    O(1)空间解法:将链表的后半段翻转然后和前半段比较

    class Solution {
        ListNode reverse(ListNode head) {
            if (head==null || head.next==null) return head;
            ListNode pre=null, post=head;
            while (head!=null) {
                post=head.next;
                head.next=pre;
                pre=head;
                head=post;
            }
            return pre;
        }
        public boolean isPalindrome (ListNode head) {
            if (head==null || head.next==null) return true;
            ListNode slow=head, fast=head;
            while (fast!=null && fast.next!=null) {
                slow=slow.next;
                fast=fast.next.next;
            }
            slow=reverse(slow);
            while (slow!=null) {
                if (slow.val!=head.val) return false;
                slow=slow.next;
                head=head.next;
            }
            return true;
        }
    }
    

    c. 判断链表是否有环

    判断给定的链表中是否有环;扩展:你能给出空间复杂度的解法么?

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

    b. 链表环的入口结点

    https://leetcode-cn.com/problems/linked-list-cycle-ii/solution/linked-list-cycle-ii-kuai-man-zhi-zhen-shuang-zhi-/
    思路

    func detectCycle(head *ListNode) *ListNode {
        slow, fast := head, head
        for (fast != nil && fast.Next != nil) {
            slow, fast = slow.Next, fast.Next.Next
            if (slow == fast) {
                slow = head
                for (slow != fast) {
                    slow, fast = slow.Next, fast.Next
                }
                return slow
            }
        }
        return nil
    }
    

    b. 重排链表

    给定链表 1->2->3->4->5, 重新排列为 1->5->2->4->3.

    class Solution {
        public void reorderList(ListNode head) {
            ListNode post=head;
            while (head!=null && head.next!=null) {
                while (post.next.next!=null) {
                    post=post.next;
                }
                ListNode t=post.next; //重排区域的尾节点
                post.next=null;
                t.next=head.next;     //为什么要把post.next指定在这里置空,移到下一行都不行
                head.next=t;
                head=post=t.next;
            }
        }
    }
    

    b. 生成相加链表

    给定两个这种链表,请生成代表两个整数相加值的结果链表。
    例如:链表 1 为 9->3->7,链表 2 为 6->3,最后生成新的结果链表为 1->0->0->0。

    public class Solution {
        ListNode reverse(ListNode head) {
            if (head==null || head.next==null) return head;
            ListNode pre=null, post=head;
            while (head!=null) {
                post=head.next;
                head.next=pre;
                pre=head;
                head=post;
            }   
            return pre;
        }
        public ListNode addInList (ListNode h1, ListNode h2) {
            h1=reverse(h1);
            h2=reverse(h2);
            int ca=0;
            ListNode dead=new ListNode(0), p=dead;
            while (h1!=null || h2!=null || ca!=0) {
                int a=h1==null ? 0 : h1.val;
                int b=h2==null ? 0 : h2.val;
                ca+=a+b;
                ListNode t=new ListNode(ca%10);
                t.next=p.next; //头插法
                p.next=t;
                ca/=10;
                if (h1!=null) h1=h1.next;
                if (h2!=null) h2=h2.next;
            }
            return dead.next;
        }
    }
    

    b. 删除链表中的重复元素

    给出一个升序排序的链表,删除链表中的所有重复出现的元素,只保留原链表中只出现一次的元素。
    给出的链表为1→1→1→2→3, 返回2→3

    思路:双指针

    class Solution {
        public ListNode deleteDuplicates(ListNode head) {
            if (head==null || head.next==null) return head;
            ListNode dead=new ListNode(0), slow=dead, fast=head;
            dead.next=head;    
            while (fast!=null && fast.next!=null) {
                if (fast.val!=fast.next.val) { //证明fast.val是需要保留的
                    slow=fast;
                } else {
                    while (fast.next!=null && fast.next.val==fast.val) //一直遍历到重复元素子链表的最后一个元素
                        fast=fast.next;
                    slow.next=fast.next; //抹掉重复的全部元素
                }
                fast=fast.next;
            }
            return dead.next;
        }
    }
    

    a. 排序链表

    按 升序 排列并返回 排序后的链表

    思路:归并排序

    class Solution:
        def sortList(self, head: ListNode) -> ListNode:
            def merge(l,r):
                dead=ListNode(-1)
                p=dead
                while l and r:
                    if l.val<r.val: p.next, l = l, l.next
                    else: p.next, r = r, r.next
                    p=p.next
                if l: p.next=l
                else: p.next=r
                return dead.next
            def merge_sort(head):
                if not head or not head.next: 
                    return head
                # print(head.val)
                #将链表分成两半
                slow,fast=head,head.next.next
                while fast and fast.next:
                    slow=slow.next
                    fast=fast.next.next
                r=merge_sort(slow.next)
                slow.next=None
                l=merge_sort(head)
                #双指针合并
                return merge(l,r)
            return merge_sort(head)
    

    快排:代办

    
    

    b. 分隔链表

    给定一个链表和一个特定值 x,对链表进行分隔,使得所有小于 x 的节点都在大于或等于 x 的节点之前。
    你应当保留两个分区中每个节点的初始相对位置。

    思路:双指针,注意链表的循环引用问题,b.next可能不为空,b.next可能就是a的结尾,从而导致这种情况:a->b->a

    class Solution:
        def partition(self, head: ListNode, x: int) -> ListNode:
            dead1,dead2=ListNode(0),ListNode(0)
            a,b=dead1,dead2
            while head:
                if head.val<x:
                    a.next=head
                    a=a.next
                else:
                    b.next=head
                    b=b.next
                head=head.next
            a.next=dead2.next
            b.next=None
            return dead1.next
    

    b. 排序链表

    归并:将链表不断切分成两部分(快慢指针实现,注意还要断开),直到剩下两个结点,然后 merge,返回上层

    func merge(l, r *ListNode) *ListNode {
        dead := new(ListNode)
        cur := dead
        for (l != nil && r != nil) {
            if (l.Val < r.Val) {
                cur.Next, l = l, l.Next
            } else {
                cur.Next, r = r, r.Next
            }
            cur = cur.Next
        }
        if (l != nil) { cur.Next = l }
        if (r != nil) { cur.Next = r }
        return dead.Next
    }
    func merge_sort(head *ListNode) *ListNode {
        if (head == nil || head.Next == nil) {
            return head
        }
        slow, fast := head, head.Next.Next
        for (fast != nil && fast.Next != nil) {
            slow, fast = slow.Next, fast.Next.Next
        }
        r := merge_sort(slow.Next)
        slow.Next = nil
        l := merge_sort(head)
        return merge(l, r)
    }
    func sortList(head *ListNode) *ListNode {
        return merge_sort(head)
    }
    
  • 相关阅读:
    第1次作业
    第0次作业
    总结报告
    第14、15周作业
    第七周作业
    第六周作业
    第四周作业
    第四次作业
    第三次作业
    2018第二次作业
  • 原文地址:https://www.cnblogs.com/wdt1/p/13846418.html
Copyright © 2011-2022 走看看