6月23日算法日记

197 阅读3分钟

6.23算法日记

1.环形链表

image-20220623210603216

解法

1.追击法

思路:

在一个环形的跑道上面,A和B从同一起点出发但是A的速度比B的速度快,那么久而久之A一定可以领先B一圈并且追上B的。

所以综上所述,在环形链表中定义两个指针分别为fastp和slowp,fastp每次向前走两个单位,而slowp每次向前走一个单位;如果链表不存在环形链表的话fastp.next是一定会为null的,反之存在环形链表的话fasp.next和fasp.next.next永远不会为null的,那么此时进入while循环分别将slowp和fastp向前移动一个单位和两个单位,一旦slowp和fastp处在了同一位置,那么就说明了链表存在环。

其实也可以将fastp和slowp每次移动的单位长度变的更长,但是这样会增加算法的复杂度。

var hasCycle = function(head) {
    if(head == null) return false
    //定义一个快指针和一个慢指针,fastp每次移动两个单位,slowp每次移动一个单位
    let fastp = head
    let slowp = head
    while(fastp.next != null && fastp.next.next != null) {
        fastp = fastp.next.next
        slowp = slowp.next
        if(fastp == slowp) {
            return true
        }
    }
    return false
};

2.环形链表2

image-20220623222008551

解法

追击法

思路:

前半部分思路同上一题一样,但是当快慢指针第一次相遇之后需要将slowp慢指针置于head初始位置,然后只要当两指针速度不相同,那么二者的速度就变为相同,一旦二者第二次重合了就表明重合的点为环的第一个节点

var detectCycle = function(head) {
    if(head == null) return null
    let fastp = head
    let slowp = head
    let loopExist = false
    while(fastp.next != null && fastp.next.next != null) {
        fastp = fastp.next.next
        slowp = slowp.next
        //二者第一次相遇,说明出现了环就可以跳出循环了
        if(fastp == slowp) {
            loopExist = true
            break
        }
    }
    if(loopExist) {
        slowp = head
        
        
        while(fastp != slowp) {
            slowp = slowp.next
            fastp = fastp.next
        }
        //第二次相遇就是链表入环的第一个节点
        return slowp
    }
    
    return null
};

3.相交链表

image-20220623235828874

解法

1.双指针

思路:

定义两个指针p1和p2分别指向两链表的头结点,然后每次往后推进一个单位,直至p1或p2到了链表末尾null时,再将该指针放入另一链表的头部,比如p1指针先到“null结点”了那么就将p1此时指向B链表的头结点。依次类推最后当两指针指向同一结点时即为两链表的相交结点(如果是null结点说明两链表不相交)

var getIntersectionNode = function(headA, headB) {
    if(headA == null || headB == null) return null
    //双指针
    let p1 = headA
    let p2 = headB
    while(p1 != p2) {
        p1 = p1 == null ? headB : p1.next
        p2 = p2 == null ? headA : p2.next
    }
    return p1
};
2.差值法

思路:

首先计算两个链表的长度,然后得出两个链表的长度差diff,让较长链表直接跳过diff个单位长度,较长从diff位置开始,较短链表从首位置开始,二者开始比较直到出现p1 == p2就说明该结点为相交结点,如果一直到null都没有出现p1 ==p2则说明两链表不相交

var getIntersectionNode = function(headA, headB) {
    // if(headA == null || headB == null) return null
    let l1 = 0, l2 = 0, diff = 0
    let p1 = headA, p2 = headB
    while(p1 != null) {
        l1++
        p1 = p1.next
    }
    while(p2 != null) {
        l2++
        p2 = p2.next
    }
    if(l1 > l2) {
        p1 = headA
        p2 = headB
        diff = l1 - l2
    } else {
        p1 = headB
        p2 = headA
        diff = l2 - l1
    }
    for(let i = 0; i < diff; i++) {
        p1 = p1.next
    }
    while(p1 != null && p2 != null) {
        if(p1 == p2) {
            return p1
        }
        p1 = p1.next
        p2 = p2.next
    }
    return null
    
};