基礎算法題-鏈表相關

1. 輸入一個鏈表,從尾到頭打印鏈表每個節點的值。

先遞歸,再添加節點的值即可。
代碼如下:

ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
    ArrayList<Integer> array = new ArrayList<Integer>();
    if (listNode != null) {
        array = printListFromTailToHead(listNode.next);
        array.add(listNode.val);
    }
    return array;
}
2. 輸入一個鏈表,輸出該鏈表中倒數第k個結點。

設置兩個指針指向鏈表頭,一個先走K步,然後兩個指針一起向後移動,第一個指針到尾部時候,第二個指針即倒數第K個結點。
代碼如下:

ListNode FindKthToTail(ListNode head, int k) {
    if (head == null | k < 0) return null;
    ListNode pointer1 = head;
    ListNode pointer2 = head;
    int count = 1;
    while (pointer2.next != null) {
        if (count < k) {
            pointer2 = pointer2.next;
            count++;
        } else {
            pointer2 = pointer2.next;
            pointer1 = pointer1.next;
        }
    }
    if (count == k)
        return pointer1;
    else
        return null;
}
3. 輸入一個鏈表,反轉鏈表後,輸出鏈表的所有元素。

用兩種方式來解決,第一種遞歸解決,考慮有一個k結點,將k結點後鏈表逆轉後的頭結點返回,此時k結點指向的結點是逆轉後鏈表的尾部結點,將k結點移到逆轉後鏈表的尾部即可。
代碼如下:

ListNode ReverseList(ListNode head) {
    if (head == null) return null;
    //遞歸解決
    if (head.next == null)
        return head;
    ListNode head1 = ReverseList(head.next);
    head.next.next = head;
    head.next = null;
    return head1;
}

第二種方式,通過在原始鏈表中操作,採用頭插法即可逆置。
代碼如下:

ListNode ReverseList(ListNode head) {
    if (head == null) return null;
    ListNode pointer = head.next;
    ListNode pointer1 = head;
    while (pointer != null) {
        head.next = pointer.next;
        pointer.next = pointer1;
        pointer1 = pointer;
        pointer = head.next;
    }
    return pointer1;
}
4. 輸入兩個單調遞增的鏈表,輸出兩個鏈表合成後的鏈表,當然我們需要合成後的鏈表滿足單調不減規則。

兩種方式解決,一種遞歸,首先比較兩個鏈表的頭結點,獲得了一個較小的結點,此時應該遞歸比較結點後的鏈表和另一個鏈表即可。
代碼如下:

ListNode Merge(ListNode list1, ListNode list2) {
    if (list1 == null) return list2;
    if (list2 == null) return list1;
    ListNode pointer1 = list1;
    ListNode pointer2 = list2;
    //遞歸實現
    if (list1.val <= list2.val) {
        pointer1 = list1;
        pointer1.next = Merge(list1.next, list2);
    } else {
        pointer1 = list2;
        pointer1.next = Merge(list1, list2.next);
    }
    return pointer1;
}

第二種迭代解決。採用尾插法,不斷的將較小的結點插入。代碼如下:

ListNode Merge(ListNode list1, ListNode list2) {
    if (list1 == null) return list2;
    if (list2 == null) return list1;
    ListNode pointer1 = list1;
    ListNode pointer2 = list2;
    ListNode head = new ListNode(0);
    ListNode rear = head;//尾插法
    while (pointer1 != null && pointer2 != null) {
        if (pointer1.val <= pointer2.val) {
            rear.next = pointer1;
            rear = pointer1;
            pointer1 = pointer1.next;
        } else if (pointer1.val > pointer2.val) {
            rear.next = pointer2;
            rear = pointer2;
            pointer2 = pointer2.next;
        }
    }
    if (pointer1 != null)
        rear.next = pointer1;
    else if (pointer2 != null)
        rear.next = pointer2;
    return head.next;
}
5. 輸入一個複雜鏈表(每個節點中有節點值,以及兩個指針,一個指向下一個節點,另一個特殊指針指向任意一個節點),返回結果爲複製後複雜鏈表的head。

首先在原始複雜鏈表上進行復制結點操作,例如1->2->3變爲1->1->2->2->3->3。然後將特殊的指針也進行賦值。每個特殊指針不爲空的結點後一個結點的特殊指針指向,前一個結點特殊指針指向的結點的下一個。最後將結點分離出來即可。
代碼如下:

/*
public class RandomListNode {
    int label;
    RandomListNode next = null;
    RandomListNode random = null;

    RandomListNode(int label) {
        this.label = label;
    }
}
*/
RandomListNode Clone(RandomListNode pHead) {
    if (pHead == null) return null;
    RandomListNode pointer = pHead;
    while (pointer != null) {
        RandomListNode node = new RandomListNode(pointer.label);
        node.next = pointer.next;
        pointer.next = node;
        pointer = node.next;
    }
    pointer = pHead;
    while (pointer != null) {
        if (pointer.random == null)
            pointer.next.random = null;
        else {
            pointer.next.random = pointer.random.next;
        }
        pointer = pointer.next.next;
    }
    pointer = pHead;
    RandomListNode result = pHead.next;
    while (pointer != null) {
        RandomListNode node = pointer.next;
        pointer.next = pointer.next.next;
        pointer = pointer.next;
        if (pointer != null && pointer.next != null) {
            node.next = pointer.next;
        }
    }
    return result;
}
6. 輸入兩個鏈表,找出它們的第一個公共結點。

有多種方式,這裏介紹兩種,可以用兩個棧將兩個鏈表結點保存,然後兩個棧同時出棧進行對比即可,另一個先計算鏈表長度,然後進行比對。這裏只給出第二種的代碼,如下:

ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
    int len1 = 0, len2 = 0;
    if (pHead1 == null | pHead2 == null) return null;
    ListNode pointer1 = pHead1, pointer2 = pHead2;
    while (pointer1 != null) {
        len1++;
        pointer1 = pointer1.next;
    }
    while (pointer2 != null) {
        len2++;
        pointer2 = pointer2.next;
    }
    pointer1 = pHead1;
    pointer2 = pHead2;
    int more = Math.abs(len1 - len2);
    if (len1 <= len2) {
        pointer2 = pHead1;
        pointer1 = pHead2;
    }
    while (pointer1 != null && pointer2 != null) {
        if (more > 0) {
            pointer1 = pointer1.next;
            more--;
        } else {
            if (pointer1 == pointer2) {
                return pointer1;
            }
            pointer1 = pointer1.next;
            pointer2 = pointer2.next;
        }
    }
    return pointer1;
}
7. 一個鏈表中包含環,請找出該鏈表的環的入口結點。

設置三個指針,一個指針走兩步,第二個指針走一步,第三個指針在表頭。等兩個指針在鏈表中相遇時候,第二個指針和第三個指針同時出發,按一步長走即可,相遇即爲入口結點。
代碼如下:

ListNode EntryNodeOfLoop(ListNode pHead) {
    if (pHead == null | pHead.next == null) return null;
    ListNode pointer1 = pHead, pointer2 = pHead;
    boolean flag = true;
    while (flag) {
        pointer1 = pointer1.next;
        pointer2 = pointer2.next.next;
        if (pointer1 == pointer2) {
            flag = false;
        }
    }
    pointer1 = pHead;
    if (pointer1 == pointer2) {
        flag = true;
    }
    while (!flag) {
        pointer1 = pointer1.next;
        pointer2 = pointer2.next;
        if (pointer1 == pointer2) {
            flag = true;
        }
    }
    return pointer2;
}
8. 在一個排序的鏈表中,存在重複的結點,請刪除該鏈表中重複的結點,重複的結點不保留,返回鏈表頭指針。 例如,鏈表1->2->3->3->4->4->5 處理後爲 1->2->5。

遞歸實現,當某結點沒有重複,則此結點指向後續結點的處理返回的鏈表。若有重複,則將結點迭代至最後一個重複結點處,然後後續結點處理返回的鏈表頭結點即頭結點,也就是會略過這個結點。
代碼如下:

ListNode deleteDuplication(ListNode pHead) {
    if (pHead == null || pHead.next == null) {
        return pHead;
    }
    ListNode head = pHead;
    boolean flag = false;
    int val = pHead.val;
    while (pHead.next != null && val == pHead.next.val) {
        pHead = pHead.next;
        flag = true;
    }
    if (!flag) {
        head.next = deleteDuplication(pHead.next);
    } else {
        head = deleteDuplication(pHead.next);
    }
    return head;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章