目录

牛客算法top101

牛客算法top101

链表

BM1 反转链表

题目

  • 给定一个单链表的头结点pHead(该头节点是有值的,比如在下图,它的val是1),长度为n,反转该链表后,返回新链表的表头。
  • 链接

解答

  • 步骤
    • step 1:优先处理空链表,空链表不需要反转。
    • step 2:我们可以设置两个指针,一个当前节点的指针,一个上一个节点的指针(初始为空)。
    • step 3:遍历整个链表,每到一个节点,断开当前节点与后面节点的指针,并用临时变量记录后一个节点,然后当前节点指向上一个节点。
    • step 4:再轮换当前指针与上一个指针,让它们进入下一个节点及下一个节点的前序节点。
  • 代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {
        //如果是空链表就直接返回
        if(head==null){
            return head;
        }
        ListNode pre=null;
        ListNode cur=head;
        while(cur!=null){
            ListNode temp = cur.next; //断开链表,要记录后续一个
            cur.next = pre; //当前的next指向前一个
            pre = cur; //前一个更新为当前
            cur = temp; //当前更新为刚刚记录的后一个
        }
        return pre;
    }
}

BM2 反转链表内指定区间

题目

  • 将一个节点数为 size 链表 m 位置到 n 位置之间的区间反转,要求时间复杂度 O(n)O(n),空间复杂度 O(1)O(1)。
  • 链接

解答

  • 步骤

    肯定是要先找到了第m个位置才能开始反转链表,而反转的部分就是从第m个位置到第n个位置。

    • step 1:我们可以在链表前加一个表头,后续返回时去掉就好了,因为如果要从链表头的位置反转,也很方便。
    • step 2:使用两个指针,一个指向当前节点,一个指向前序节点。
    • step 3:依次遍历链表,到第m个的位置。
    • step 4:对于从m到n这些个位置的节点,依次断掉指向后续的指针,反转指针方向。
    • step 5:返回时去掉我们添加的表头。
  • 代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public class Solution {
    /**
     * 
     * @param head ListNode类 
     * @param m int整型 
     * @param n int整型 
     * @return ListNode类
     */
    public ListNode reverseBetween (ListNode head, int m, int n) {
        // write code here
        ListNode pre=null;
        ListNode cur=head;
        for(int i=1; i<m;i++){
            pre=cur;
            cur=cur.next;
        }
        for(int i=m;i<n;i++){
            //头插法
            ListNode temp=cur.next;
            cur.next=temp.next;
            temp.next=pre.next;
            pre.next=temp;
        }
        return head;
    }
}

BM3 合并两个排序的链表

题目

  • 输入两个递增的链表,单个链表的长度为n,合并这两个链表并使新链表中的节点仍然是递增排序的。 要求:空间复杂度 O(1)O(1),时间复杂度 O(n)O(n)

  • 示例

    1
    
    如输入{1,3,5},{2,4,6}合并后的链表为{1,2,3,4,5,6}所以对应的输出为{1,2,3,4,5,6}
    
  • 链接

解答

  • 步骤
    • 如果一个链表为空,直接返回另一个链表
    • 两个链表的表头元素进行比较,将最小的加入到新链表
    • 把剩下的链表的结点加入到新链表
  • 代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        //如果一个链表为空,直接返回另一个链表
        if(list1==null){
            return list2;
        }
        if(list2==null){
            return list1;
        }
        //两个链表的表头元素进行比较,将最小的加入到新链表
        ListNode head=new ListNode(0);
        ListNode cur=head;
        while(list1!=null&&list2!=null){
            //比较两链表的首元素
            if(list1.val<list2.val){
                //把小的加入到新链表
                cur.next=list1;
                //list1往下
                list1=list1.next;
            }else{
                cur.next=list2;
                list2=list2.next;
            }
            //新链表往下
            cur=cur.next;
        }
        //把剩下的链表的结点加入到新链表
        if(list2!=null){
            cur.next=list2;
        }
        if(list1!=null){
            cur.next=list1;
        }
       return head.next;
    }
}

BM4 判断链表是否有环

题目

  • 描述:给定一个链表,判断是否有环
  • 链接

解答

  • 思路:使用快慢双指针遍历,如果快慢指针为null,说明无环,否则快指针迟早会追上慢指针,两者相遇,说明有环
  • 代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        if(head==null) return false;
        ListNode fast=head;
        ListNode slow=head;
        while(fast.next!=null&&fast.next.next!=null){
            fast=fast.next.next;
            slow=slow.next;
            //相遇,说明有环
            if(fast==slow){
                return true;
            }
        }
        //退出while,说明fast到链表尾遇到了null,无环
        return false;
    }
}

BM5 找出链表中环的入口

题目

  • 描述:给定一个链表,如果有环,找出它的入口
  • 链接

解答

  • 思路
  • 步骤
    • 使用判断链表中是否有环中的方法判断链表是否有环,并找到相遇的节点
    • 慢指针继续在相遇节点,快指针回到链表头,两个指针同步逐个元素逐个元素开始遍历链表。
    • 再次相遇的地方就是环的入口
  • 代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import java.util.*;
/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public ListNode hasCycle(ListNode head) {
        if(head == null) //先判断链表为空的情况
            return null;
        ListNode fast = head; //快慢双指针
        ListNode slow = head;
        while(fast != null && fast.next != null){ //如果没环快指针会先到链表尾
            fast = fast.next.next; //快指针移动两步
            slow = slow.next; //慢指针移动一步
            if(fast == slow) //相遇则有环,返回相遇的位置
                return slow;
        }
        return null; //到末尾说明没有环,返回null
    }
    
    public ListNode EntryNodeOfLoop(ListNode pHead) {
        ListNode slow = hasCycle(pHead);
        if(slow == null) //没有环
            return null;
        ListNode fast = pHead; //快指针回到表头
        while(fast != slow){ //再次相遇即是环入口
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

BM6 链表中的倒数第k个节点

题目

  • 一个长度为n的链表,返回原链表中从倒数第k个结点至尾节点的全部节点
  • 如果该链表长度小于k,请返回一个长度为 0 的链表
  • 链接

解答

  • 思路:让两个指针一前一后,相隔刚好为k,这样,当快指针遍历到链表尾时,满指针刚好在倒数的第k个位置
  • 代码
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
import java.util.*;

/*
 * public class ListNode {
 *   int val;
 *   ListNode next = null;
 *   public ListNode(int val) {
 *     this.val = val;
 *   }
 * }
 */

public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param pHead ListNode类
     * @param k int整型
     * @return ListNode类
     */
    public ListNode FindKthToTail (ListNode pHead, int k) {
        // write code here
        ListNode fast=pHead;
        ListNode slow=pHead;
        //先让快指针走到顺数第k个位置
        for(int i=0;i<k;i++){
            if(fast!=null){
                fast=fast.next;
            }else{
                //没有到第k个位置就为空了,说嘛链表长度小于k,返回null
                return null;
            }
        }
        //slow、fast一起往下走,当fast走到底时,slow指向倒数第k个
        while(fast!=null){
            fast=fast.next;
            slow=slow.next;
        }
        return slow;
    }
}

标题

题目

解答

  • 思路

  • 步骤

  • 代码