关于链表经典算法题都在这里了

2019-05-16  本文已影响0人  bestchenq

1.单链表反转LeetCode 206

//非递归解法
public ListNode reverseList(ListNode head) {
    //长度为0或1直接返回
    if (head == null || head.next == null) {
        return head;
    }
    ListNode currNode = head;
    ListNode preNode = null;
    //临时变量存储下一个
    ListNode nextTemp = null;
    while (currNode != null) {
        nextTemp = currNode.next;
        currNode.next = preNode;
        preNode = currNode;
        currNode = nextTemp;
    }
    return preNode;
}

2.链表中环的检测 (LeetCode 141)

//典型的快慢指针的思想。
//除此之外,当换不是无限大的时候我们也可以用死循环来判断有没有环,循环一段时间,看看next是不是为null.
public boolean hasCycle(ListNode head) {
    if (head == null || head.next == null) {
        return false;
    }

    ListNode slow = head;
    ListNode fast = head;

    while (slow != null && fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;

        if (slow == fast) {
            return true;
        }
    }
    return false;
}

3.求链表中环开始结点 (LeetCode 142)
解题思路:
1.首先通过快慢指针的方法判断链表是否有环;
2.接下来如果有环,则寻找入环的第一个节点。具体的方法为,首先假定链表起点到入环的第一个节点A的长度为a【未知】,到快慢指针相遇的节点B的长度为(a + b)【这个长度是已知的】。现在我们想知道a的值,注意到快指针fast始终是慢指针slow走过长度的2倍,所以慢指针slow从B继续走(a + b)又能回到B点,如果只走a个长度就能回到节点A。但是a的值是不知道的,解决思路是曲线救国,注意到起点到A的长度是a,那么可以用一个从起点开始的新指针result和从节点B开始的慢指针slow同步走,相遇的地方必然是入环的第一个节点A。 文字有点绕,画个图就一目了然了.

public static ListNode detectCycle(ListNode head) {
    ListNode fast = head;
    ListNode slow = head;
    ListNode result = head;

    boolean hasCycle = false;
    while (fast != null && fast.next != null && slow != null) {
        fast = fast.next.next;
        slow = slow.next;

        //判断是否有环
        if (slow == fast) {
            hasCycle = true;
            break;
        }
    }

    if (hasCycle) {
        while (result != slow) {
            result = result.next;
            slow = slow.next;
        }
        return result;
    }
    return null;
}

4.两个有序链表合并 (LeetCode 21)

public static ListNode mergeTwoLists(ListNode l1, ListNode l2) {
    if (l1 == null || l2 == null) {
        return l1 == null ? l2 : l1;
    }

    ListNode temp = new ListNode(0);
    ListNode result = temp;

    while (l1 != null && l2 != null) {
        if (l1.val <= l2.val) {
            temp.next = l1;
            l1 = l1.next;
        } else {
            temp.next = l2;
            l2 = l2.next;
        }
        temp = temp.next;
    }

    //如果l1或者l2任何一个为空,就将另一个直接接在尾部。
    if (l1 == null) {
        temp.next = l2;
    } else {
        temp.next = l1;
    }
    return result.next;
}

5.删除链表的倒数第N个结点 (LeetCode 19)

//解法一,两次遍历。正常的思维是先求出链表的长度,然后从头到尾去遍历。
public static ListNode removeLastN(ListNode head, int n) {
    int len = 0;
    ListNode point = head;

    //遍历链表得出总长度
    while (point != null) {
        point = point.next;
        len++;
    }

    //得到是删除正数第几个
    int k = len - n;
    //指针,指向head

    ListNode point2 = new ListNode(0);
    ListNode result = point2;
    point2.next = head;

    //前面的照常遍历
    for (int i = 0; i <= k; i++) {
        point2 = point2.next;
    }
    //第K个就删除
    point2.next = point2.next.next;
    return result.next;
}
//解法二,一次遍历。这一种解法是利用了快慢指针,一般情况下不太容易想出此种方法。
public static ListNode onceRemoveLastN(ListNode head, int n) {
    //慢指针
    ListNode slow = new ListNode(-1);
    slow.next = head;

    ListNode result = slow;

    //快指针
    ListNode fast = new ListNode(-1);
    fast.next = head;

    while (fast != null) {
        fast = fast.next;
        //快指针先走n步
        if (n < 0) {
            slow = slow.next;
        }
        n--;
    }
    slow.next = slow.next.next;

    return result.next;
}

关于删除链表结点的问题:

//方法一:
  preNode.next = preNode.next.next;  //preNode为node的前面一个结点
  
  //方法二:
  node.val = node.next.val;
  node.next = node.next.next;

同样,这两种方法要考虑边界情况。

6.求链表的中间结点 (N等分点)

//二等分代码
public static ListNode halfNode(ListNode head) {
    ListNode fast = new ListNode(0);
    fast.next = head;

    ListNode slow = new ListNode(0);
    slow.next = head;

    while (fast != null && fast.next != null) {
        fast = fast.next.next;
        slow = slow.next;
    }
    return slow;
}

如果是N等分的话也是用快慢指针的思想,快指针一次性走N步,慢指针一次走一步,最后快指针走到终点的时候,慢指针所在的结点就是N等分点(注意验证一些边界情况)。

上一篇下一篇

猜你喜欢

热点阅读