算法学习(3)链表高频面试算法题

1、两个链表的第一个公共子结点

题目:牛客JZ52
输入两个无环的单向链表,找出它们的第一个公共结点,如果没有公共节点则返回空。
例如,输入{1,2,3},{4,5},{6,7}时,两个无环的单向链表的结构如下图所示:
在这里插入图片描述
可以看到它们的第一个公共结点的结点值为6,所以返回结点值为6的结点。

方法一:哈希和集合。先将一个链表元素全部存到Map里,然后一边遍历第二个链表,一边检测Hash中是否存在当前结点,如果有交点,则一定能检测出来。

Java代码:

public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
    Set<ListNode> set = new HashSet<>();
    while(pHead1 != null){
        set.add(pHead1);
        pHead1 = pHead1.next;
    }
    while(pHead2 != null){
        if(set.contains(pHead2)){
            return pHead2;
        }
        pHead2 = pHead2.next;
    }
    return null;
}

Python代码:

def FindFirstCommonNode(self , pHead1 , pHead2):
    s = set()
    p = pHead1
    q = pHead2
    while(p):
        s.add(p)
        p = p.next
    while(q):
        if q in s:
            return q
        q = q.next
    return None

由于C语言基础包里没有定义集合类型,如果用集合需要先自己构建一个,或者引入外部包,因此不提供代码。

方法二:使用栈。分别将两个链表的结点压入两个栈,然后分别出栈,如果相等就继续出栈,一直找到最晚出栈的那一组。这种方式需要两个O(n)的空间,不是最好。

Java代码:

public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2){
    Stack<ListNode> stackA = new Stack<>();
    Stack<ListNode> stackB = new Stack<>();
    while(pHead1 != null){
        stackA.push(pHead1);
        pHead1 = pHead1.next;
    }
    while(pHead2 != null){
        stackB.push(pHead2);
        pHead2 = pHead2.next;
    }
    ListNode preNode = null;
    while(stackA.size() > 0 && stackB.size() > 0){
        if(stackA.peek() == stackB.peek()){  //stack.peek()只能返回栈顶有元素,不能删除栈顶元素
            preNode = stackA.pop();   //stack.pop()可以返回栈顶元素
            stackB.pop();   //stack.pop()是出栈的意思,也就是删除栈顶元素
        }
        else{
            break;
        }
    }
    return preNode;
}

Python代码:

def FindFirstCommonNode(self , pHead1 , pHead2):
    s1, s2 = [], []
    p, q = pHead1, pHead2
    while p:
        s1.append(p)
        p = p.next
    while q:
        s2.append(q)
        q = q.next
    ans = None
    i, j = len(s1) - 1,len(s2) - 1
    while i >= 0 and j >= 0 and s1[i] == s2[j]:
        ans = s1[i]
        i, j = i - 1, j - 1
    return ans

由于C语言基础包里没有提供栈类型,如果用栈需要先自己构建一个,或者引入外部包,因此不提供代码。

方法三:拼接两个字符串(双指针法)。题中两个链表分别为{1,2,3,6,7}和{4,5,6,7}。有两种形式拼接两个链表:①:1-2-3-6-7-4-5-6-7;②4-5-6-7-1-2-3-4-6-7。
我们发现拼接从最后的6开始,后面的结点一样了,6 就是要找的结点,所以可以通过拼接的方式来寻找交点。
因此遍历拼接后的两个链表就能找到交点。
但是建立新的链表太浪费空间了,我们只需要在每个链表访问完之后,调整到下一链表的表头继续访问就行了。(这操作是真的牛了)

但是个人感觉这个拼接链表不正确,因为两个链表的6结点是一样的,真正拼接时应该会形成一个有环链表,此时两个链表的结点7不一样了,所以······不知道该怎么解释。
但又好在本题的解法不用拼接链表,只需要在每个链表访问之后,调整到下一链表的表头继续访问就行了。

Java代码:

public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
    if(pHead1 == null || pHead2 == null){
        return null;
    }
    ListNode p1 = pHead1;
    ListNode p2 = pHead2;
    while(p1 != p2){
        p1 = p1.next;
        p2 = p2.next;
        //这个地方的if是很重要的,如果没有这个if,那么在两个链表没有交点时,上面的while就会陷入死循环
        if(p1 != p2){
            //一个链表访问完了就跳到另外一个链表继续访问
            if(p1 == null){
                p1 = pHead2;
            }
            //一个链表访问完了就跳到另外一个链表继续访问
            if(p2 == null){
                p2 = pHead1;
            }
        }
    }
    return p1;
}
}

Python代码:

def FindFirstCommonNode(self , pHead1 , pHead2):
    node1 = pHead1
    node2 = pHead2
    
    while node1 != node2:
        node1 = node1.next if node1 else pHead2
        node2 = node2.next if node2 else pHead1
        
    return node1

C语言代码:

struct ListNode* FindFirstCommonNode(struct ListNode* pHead1, struct ListNode* pHead2 ) {
    if(pHead1 == NULL || pHead2 == NULL){
        return NULL;
    }
    struct ListNode* p1 = pHead1;
    struct ListNode* p2 = pHead2;
    while(p1 != p2){
        p1 = p1->next;
        p2 = p2->next;
        if(p1 != p2){

            //一个链表访问完了就跳到另外一个链表继续访问
            if(p1 == NULL){
                p1 = pHead2;
            }
            if(p2 == NULL){
                p2 = pHead1;
            }
        }
    }
    return p1;
}

方法四:差和双指针。假如公共子结点一定存在第一遍历,就是两个链表都不为空的意思,假设La长度为L1,Lb长度为L2。则 |L2 -L1| 就是两链表长度的差值。第二轮遍历,长的先走 |L2-L1| ,然后两个链表同时向前走,结点一样的时候就是公共结点了。

Java代码:

public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) {
    if(pHead1 == null || pHead2 == null){
        return null;
    }
    ListNode current1 = pHead1;
    ListNode current2 = pHead2;
    int l1 = 0;
    int l2 = 0;
    while(current1 != null){
        current1 = current1.next;
        l1 ++;
    }
    while(current2 != null){
        current2 = current2.next;
        l2 ++;
    }

    current1 = pHead1;
    current2 = pHead2;

    int sub = l1 > l2 ? l1 - l2 : l2 - l1;

    if(l1 > l2){
        int a = 0;
        while(a < sub){
            current1 = current1.next;
            a ++;
        }
    }
    else{
        int a = 0;
        while(a < sub){
            current2 = current2.next;
            a ++;
        }
    }
    while(current1 != current2){
        current1 = current1.next;
        current2 = current2.next;
    }
    return current1;
}

Python代码:

def FindFirstCommonNode(self , pHead1 , pHead2):
        s1 = 0
        s2 = 0
        p = pHead1
        q = pHead2

        while p:
            p = p.next
            s1 += 1
        while q:
            q = q.next
            s2 += 1

        p = pHead1
        q = pHead2
        #以下两个for循环只会执行一个
        for i in range(s1 - s2):
            p = p.next
        for i in range(s2 - s1):
            q = q.next

        while p and q and p != q:
            p = p.next
            q = q.next
        return p

C语言代码:

struct ListNode* FindFirstCommonNode(struct ListNode* pHead1,
                                     struct ListNode* pHead2 ) {
    if (pHead1 == NULL || pHead2 == NULL) {
        return NULL;
    }
    struct ListNode* current1 = pHead1;
    struct ListNode* current2 = pHead2;

    int l1 = 0;
    int l2 = 0;

    while (current1 != NULL) {
        current1 = current1->next;
        l1 ++;
    }
    while (current2 != NULL) {
        current2 = current2->next;
        l2 ++;
    }

    current1 = pHead1;
    current2 = pHead2;

    int sub = l1 > l2 ? l1 - l2 : l2 - l1;

    //长的先走sub步
    if (l1 > l2) {
        int a = 0;
        while (a < sub) {
            current1 = current1->next;
            a ++;
        }
    } 
    else {
        int a = 0;
        while (a < sub) {
            current2 = current2->next;
            a ++;
        }
    }
    //同时遍历两个链表
    while(current1 != current2){
        current1 = current1->next;
        current2 = current2->next;
    }
    return current1;
}

2、判断链表是否为回文序列

题目:LeetCode234
给你一个单链表的头节点 head,请你判断该链表是否为回文链表。如果是,返回 true;否则,返回 false。
示例:
在这里插入图片描述
输入:head = [1,2,2,1]
输出:true

本题方法有很多,简单举例。

方法一:将链表元素都赋值到数组中,然后可以从数组两端向中间对比。这种方法会被视为逃避链表,面试不能这么干。
注意:本方法只有Python核心代码。

def isPalindrome(self, head):
    """
    :type head: ListNode
    :rtype: bool
    """
    cur, length = head, 0
    result = []
    while cur is not None:
        length += 1
        result.append(cur.val)
        cur = cur.next
    #运用双指针,分别从前和从后遍历链表
    left, right = 0, length - 1
    while left < right:
        if result[left] != result[right]:
            return False
        left += 1
        right -= 1
    return True

方法二:将链表元素全部压栈,然后一边出栈,一边重新遍历链表,一边比较两者元素值,只要有一个元素值,那就不是回文序列。
注意:本方法只有Java核心代码。

public boolean isPalindrome(ListNode head) {
    ListNode temp = head;
    //创建一个栈
    Stack<Integer> stack = new Stack();
    //把链表结点的值存放到栈中
    while(temp != null){
        stack.push(temp.val);
        temp = temp.next;
    }
    while(head != null){
        if(head.val != stack.pop())
            return false;
        head = head.next;
    }
    return true;
}

由于C语言基础包里没有提供栈类型,如果用栈需要先自己构建一个,或者引入外部包,因此不提供代码。

3、合并有序链表(合并两个有序链表)

题目:LeetCode21
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:在这里插入图片描述
输入:l1 = [1,2,4], l2 = [1,3,4]
输出:[1,1,2,3,4,4]

方法:新建一个链表,然后分别遍历两个链表,每次都选择最小的结点接到新链表上,最后排完。最优美的代码写法如下:

Java代码:

public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
    //创建一个新链表
    ListNode newHead = new ListNode(-1);
    ListNode res = newHead;
    while(list1 != null && list2 != null){
        if(list1.val <= list2.val){
            newHead.next = list1;
            list1 = list1.next;
        }
        else if(list1.val > list2.val){
            newHead.next = list2;
            list2 = list2.next;
        }
        newHead = newHead.next;
    }
    //最多只有一个还未被合并完,直接接上去就行了,这是链表合并比数组合并方便的地方。
    //这方法还是挺厉害的。
    newHead.next = list1 == null? list2:list1;
    return res.next;
}

Python代码:

def mergeTwoLists(self, list1, list2):
    p = ListNode(0)
    phead = p
    while list1 and list2:
        if list1.val <= list2.val:
            p.next = list1
            list1 = list1.next
        else:
            p.next = list2
            list2 = list2.next
        p = p.next
    if list1 is not None:
        p.next = list1
    else:
        p.next = list2
    return phead.next

C语言代码:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    //这种新建一个结点是不需要指出结点的val和next的呀
    struct ListNode* prehead = (struct ListNode* )malloc(sizeof(struct ListNode));
    struct ListNode* prev = prehead;
    while(list1 != NULL && list2 != NULL){
        if(list1->val <= list2->val){
            prev->next = list1;
            list1 = list1->next;
        }
        else{
            prev->next = list2;
            list2 = list2->next;
        }
        prev = prev->next;
    }
    prev->next = list1 == NULL ? list2 : list1;
    return prehead->next;
}

4、合并有序链表(合并K个升序链表)

题目:LeetCode23
给你一个链表数组,每个链表都已经按升序排列。请你将所有链表合并到一个升序链表中,返回合并后的链表。
示例 :
输入:lists = [ [1,4,5], [1,3,4], [2,6] ]
输出:[1,1,2,3,4,4,5,6]
解释:链表数组如下:
[
1->4->5,
1->3->4,
2->6
]
将它们合并到一个有序链表中得到。
1->1->2->3->4->4->5->6

方法:先将前两个合并,之后再将后面的逐步合并进来,这样的好处是只要将两个合并的写清楚,合并K个就容易很多。

Java代码:

public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
    //创建一个新结点
    ListNode newHead = new ListNode(-1);
    ListNode res = newHead;
    while(list1 != null && list2 != null){
        if(list1.val <= list2.val){
            newHead.next = list1;
            list1 = list1.next;
        }
        else if(list1.val > list2.val){
            newHead.next = list2;
            list2 = list2.next;
        }
        newHead = newHead.next;
    }
    newHead.next = list1 == null? list2:list1;
    return res.next;
}
public ListNode mergeKLists(ListNode[] lists) {
    ListNode res = null;
    for(ListNode list:lists){
        res = mergeTwoLists(res, list);
    }
    return res;
}

Python代码:

def mergeKLists(self, lists):
    """
    :type lists: List[ListNode]
    :rtype: ListNode
    """
    def mergeTwoLists(a, b):
        merge = ListNode(-1)
        head = merge
        while a and b:
            if a.val >= b.val:
                head.next = b
                b = b.next
            else:
                head.next = a
                a = a.next
            head = head.next
        head.next = a if a else b
        return merge.next    
    if len(lists) == 0:
        return None
    res = None
    for i in range(0, len(lists)):
        res = mergeTwoLists(res, lists[i])
    return res

C语言代码:

struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
    struct ListNode* newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
    newHead->val = -1;
    newHead->next = NULL;
    struct ListNode* res = newHead;

    while(list1 != NULL || list2 != NULL){
        if(list1 != NULL && list2 != NULL){
            if(list1->val < list2->val){
                newHead->next = list1;
                newHead = newHead->next;
                list1 = list1->next;
            }
            else if(list1->val > list2->val){
                newHead->next = list2;
                newHead = newHead->next;
                list2 = list2->next;
            }
            else{
                newHead->next = list1;
                newHead = newHead->next;
                list1 = list1->next;
                newHead->next = list2;
                newHead = newHead->next;
                list2 = list2->next;
            }
        }
        else if(list1 == NULL && list2 != NULL){
            newHead->next = list2;
            list2 = list2->next;
            newHead = newHead->next;
        }
        else if(list1 != NULL && list2 == NULL){
            newHead->next = list1;
            list1 = list1->next;
            newHead = newHead->next;
        }
    }
    return res->next;
}

struct ListNode* mergeKLists(struct ListNode** lists, int listsSize) {
    struct ListNode* res = NULL;
        
        for(int i = 0; i < listsSize; i ++){
            res = mergeTwoLists(res, lists[i]);
        }
        return res;
}

5、合并有序链表(一道好题)

题目:LeetCode1669
给你两个链表 list1 和 list2 ,它们包含的元素分别为 n 个和 m 个。请你将 list1 中下标从 a 到 b 的全部节点都删除,并将list2 接在被删除节点的位置。最后返回结果链表的头指针。
下图中蓝色边和节点展示了操作后的结果:
在这里插入图片描述

方法:遍历第一个链表,找到链表1保留部分的尾结点和头结点;
遍历第二个链表,找到链表2的尾结点,将两个链表连接起来。

Java代码:

public ListNode mergeInBetween(ListNode list1, int a, int b, ListNode list2) {
    ListNode pre1 = list1, post1 = list1, post2 = list2;
    int i = 0, j = 0;
    for(i = 0; i < a - 1; i ++){
        pre1 = pre1.next;
    }
    for(j = 0; j < b + 1; j ++){
        post1 = post1.next;
    }
    pre1.next = post2;
    while(post2.next != null){
        post2 = post2.next;
    }
    post2.next = post1;
    return list1;
}

Python代码:

def mergeInBetween(self, list1, a, b, list2):
    #dummy = ListNode(0)
    #dummy.next = list1
    tmp1 = list1
    tmp2 = list1
    l1 = 0 
    l2 = 0
    while l1 < a - 1:
        tmp1 = tmp1.next
        l1 += 1
    while l2 < b + 1:
        tmp2 = tmp2.next
        l2 += 1
    tmp1.next = list2
    while list2.next:
        list2 = list2.next
    list2.next = tmp2
    return list1

C语言代码:

struct ListNode* mergeInBetween(struct ListNode* list1, int a, int b, struct ListNode* list2){
    struct ListNode* pre1 = list1;
    struct ListNode* post1 = list1; 
    struct ListNode* post2 = list2;

    int i = 0, j = 0;

    for(i = 0; i < a - 1; i ++){  //下列代码执行了(a - 1)次
        pre1 = pre1->next;
    }
    for(j = 0; j < b + 1; j ++){
        post1 = post1->next;
    }
    pre1->next = post2;
    while(post2->next != NULL){
        post2 = post2->next;
    }
    post2->next = post1;
    return list1;
}

6、寻找中间结点

题目:LeetCode876
给你单链表的头结点 head ,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。

方法:快慢指针法。fast指针一次走两步,slow指针一次走一步,当fast指针到达链表尾部时,slow必然位于中间。

Java代码:

class Solution {
    public ListNode middleNode(ListNode head) {
        ListNode slow = head;
        ListNode fast = head;
        while(fast != null && fast.next != null){
            slow = slow.next;
            fast = fast.next.next;
        }
        return slow;

    }
}

Python代码:

class Solution(object):
    def middleNode(self, head):
        """
        :type head: ListNode
        :rtype: ListNode
        """
        #if head is None:
        #    return None
        slow = head
        fast = head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
        return slow

Python代码(含本地编辑器测试):

class LinkNode(object):
    def __init__(self, val = None, next = None):
        self.val = val
        self.next = next

def init_list(nums):
    tem_node = LinkNode()
    tem = LinkNode()

    for i in nums:
        if tem_node.val == None:
            tem_node.val = i
            tem = tem_node
        else:
            tem_node.next = LinkNode(i)
            tem_node = tem_node.next
    return tem

class MiddleNode():
    def middleNode(self, head):
        if head is None:
            return None
        slow = head
        fast = head
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
        return slow

if __name__ == "__main__":
    nums = [0, 0, 3, 4, 5, 6]
    list = init_list(nums)
    middleNode = MiddleNode()
    node = middleNode.middleNode(list)
    print(node.val)

C++代码:

public:
    ListNode* middleNode(ListNode* head) {
        ListNode* slow = head;
        ListNode* fast = head;

        while(fast  != NULL && fast -> next != NULL){
            slow = slow->next;
            fast = fast->next->next;
        }
        
        return slow;

    }

7、寻找倒数第K个元素

题目:牛客HJ51
输入一个单向链表,输出该链表中倒数第k个结点,链表的倒数第1个结点为链表的尾指针。
正常返回倒数第k个结点指针,异常返回空指针。

方法:快慢指针法。先将fast向后遍历到第k+1个结点,slow仍然指向链表的第一个结点,此时指针fast与slow二者之间刚好间隔k个结点。之后两个指针同步向后走,当fast走到链表的尾部空结点时,slow指针刚好指向链表的倒数第k个结点。

Java代码:

//咳咳,以下是acm模式下的代码
import java.util.Scanner; // 头文件

class ListNode{
    int val;
    ListNode next;
}

// 注意类名必须为 Main, 不要有任何 package xxx 信息,定义的不是结构体,是类,要加public
public class Main {
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);   //开头这三句话都是原来就有的,感觉有点陌生
        // 注意 hasNext 和 hasNextLine 的区别
        while (in.hasNext()) { // 注意 while 处理多个 case
            ListNode node = new ListNode();
            node.next = null;
            ListNode n =  node;
            int N = in.nextInt(); 
            for(int i = 0; i < N; i ++){
                ListNode p = new ListNode();
                int x = in.nextInt();
                p.val = x;
                node.next = p;
                node = node.next; //也可以写成node = p;
            }
            int k = in.nextInt();
            ListNode kthNode = getKthNode(n, k);
            System.out.println(kthNode.val);
        }
    }

    public static ListNode getKthNode(ListNode n, int k){
        ListNode fast = n;
        ListNode slow = n;
        for(int i = 0; i < k; i ++){
            if(fast != null)
                fast = fast.next;
            else
                return null;
        }
        while(fast != null){
            fast = fast.next;
            slow = slow.next;
        }
        return slow;
    }
}

Python代码:

#咳咳,以下是acm模式下的代码
class ListNode(object):
    def __init__(self, val = None, next = None):
        self.val = val
        self.next = next

def GetKthFromTail(head: ListNode, k):
    fast = head
    slow = head

    for i in range(k):  #不太懂,这样就是执行了k次嘛
        if fast:
            fast = fast.next
        else:
            return None

    while fast:
        fast = fast.next
        slow = slow.next

    return slow
    

if __name__ == "__main__":
    while True:     #直接这么写就可以处理多种情况了呀,python还真是简单
        try:
            N = int(input())
            ls = input().split()
            k = int(input())

            head = ListNode(ls[0])
            cur = head
            for i in range(1, N):
                head.next = ListNode(ls[i])
                head = head.next
                
            if k:
                p_Kth = GetKthFromTail(cur, k)
                if p_Kth:
                    print(p_Kth.val)
                else:
                    print('0')
            else:
                print('0')
        except:
            break

C++代码:

//咳咳,以下是acm模式下的代码
 #include<iostream>
using namespace std;

struct ListNode{
    int val;
    ListNode* next;
    ListNode(int x): val(x), next(NULL){}
};

ListNode* FindKthToTail(ListNode* pHead, int k){
    ListNode* fast = pHead;
    ListNode* slow = pHead;
    for(int i = 0; i < k; i ++){ //0~k就是执行了k次
        if(fast != NULL)
            fast = fast->next;
        else
            return slow = NULL;//链表长度小于k的时候,返回空链表
    }
    while(fast != NULL){   //fast最后在整个链表的后一个的位置
        fast = fast->next;
        slow = slow->next;
    }
    return slow;
}

int main(){
    int n;
    while(cin >> n){
        int val;
        cin >> val;
        ListNode* head = new ListNode(val); //这样就新建了一个结点,比c语言新建一个结点简洁一些
        ListNode* p = head;
        for(int i = 1; i < n; i++){
            cin >> val;
            ListNode* a = new ListNode(val);
            p->next = a;
            p = p->next;
        }
        int k;
        cin >> k;
        if(k == 0)
            cout << "false" << endl;

        else{
            p = FindKthToTail(head, k);
            if(p != NULL)
                cout << p->val << endl;
        }
    }
    return 0;
}

8、旋转链表

题目:LeetCode61
给你一个链表的头节点 head ,旋转链表,将链表每个节点向右移动 k 个位置。
示例:
输入:head = [1,2,3,4,5], k = 2
输出:[4,5,1,2,3]
在这里插入图片描述

方法一:快慢指针法。
①有可能k大于链表长度,所以首先获取一下链表长度冷,然后k = k % len,如果k == 0,则不用旋转,直接返回头结点。否则:
②先将fast向后遍历到第k+1个结点,slow仍然指向链表的第一个结点,此时指针fast与slow二者之间刚好间隔k个结点;
③慢指针和快指针一起走;
④快指针走到链表尾部时,慢指针所在位置刚好是要断开的地方。把快指针指向的结点连接到原链表头部,慢指针指向的结点断开和下一结点的联系;
⑤返回结束时慢指针指向的下一结点。

Java代码:

class Solution {
    public ListNode rotateRight(ListNode head, int k) {
        if(head == null || k == 0){
            return head;
        }
        //这里三个变量都指向链表头结点
        ListNode temp = head;
        ListNode fast = head;
        ListNode slow = head;
        //计算出链表的长度
        int len = 0;
        while(head != null){
            head = head.next;
            len ++;
        }
        if(k % len == 0){
            return temp;
        }
        k = k % len;
        while(k > 0){
            k --;
            fast = fast.next;
        }
        while(fast.next != null){
            fast = fast.next;
            slow = slow.next;
        }
        ListNode res = slow.next;
        fast.next = temp;
        slow.next = null;
        return res;
             
    }
}

Python代码:

class Solution(object):
    def rotateRight(self, head, k):
        if head is None or head.next is None:
            return head
        num = 0
        basic_head = head
        new_head = head
        flag = head
        while head.next:
            head = head.next
            num += 1
        num += 1
        k = k % num
        if(k == 0):
            return flag
        else:
            xx = num - k
            for i in range(xx - 1):
                basic_head = basic_head.next
            temp = basic_head.next
            basic_head.next = None
            head.next = new_head
            return temp

C语言代码:

struct ListNode* rotateRight(struct ListNode* head, int k) {
    if(head == NULL || k == 0){
        return head;
    }

    //这里三个变量都指向链表头结点
    struct ListNode* temp = head;
    struct ListNode* fast = head;
    struct ListNode* slow = head;
    //统计出链表的元素个数,完成之后head就变成null了
    int len = 0;
    while(head != NULL){
        head = head->next;
        len ++;
    }

    if(k % len == 0){
        return temp;
    }

    k = k % len;
    while(k > 0){
        k --;
        fast = fast->next;
    }

    while(fast->next != NULL){
        fast = fast->next;
        slow = slow->next;
    }

    struct ListNode* res = slow->next;
    slow->next = NULL;
    fast->next = temp;
    return res;

}

方法二:我们要找倒数第K个,那么就是要找正数第Len-k+1个。因此可以先遍历一遍,计算出Len,然后直接通过计算得到需要走的步数,只会从头开始遍历,到第Len-k+1即可。同时也要通过取模来计算防止K越界。我们这里只看一下Python的实现:

Python代码(本地编辑器测试代码):

class LinkNode(object):
    def __init__(self, val = None, next = None):
        self.val = val
        self.next = next

def init_list(nums):
    tem_node = LinkNode()
    tem = LinkNode()

    for i in nums:
        if tem_node.val == None:
            tem_node.val = i
            tem = tem_node
        else:
            tem_node.next = LinkNode(i)
            tem_node = tem_node.next
    return tem


class RotateRight:
    def rotateRight(self, head, k):
        if head is None or head.next is None:
            return head
        num = 0
        basic_head = head
        new_head = head
        flag = head
        while head.next:
            head = head.next
            num += 1
        num += 1
        k = k % num
        if(k == 0):
            return flag
        else:
            xx = num - k

            for i in range(xx - 1):
                basic_head = basic_head.next
            temp = basic_head.next
            basic_head.next = None
            head.next = new_head
            return temp

#打印链表
def print_list(head):
    if not head or not head.next:
        return []#空数组的意思
    result = []
    while head:
        result.append(head.val)
        head = head.next
    return result

if __name__ == "__main__":
    #先构造题目要求的链表
    nums = [1, 2, 3, 4, 5]
    k = int(input())
    list = init_list(nums)
    rotateRight = RotateRight()
    flag = rotateRight.rotateRight(list,k)
    print(print_list(flag))

9、删除特定结点

题目:LeetCode203
给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。
示例:
输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]
在这里插入图片描述

方法:①创建一个虚拟链表头dummyHead,使其next指向head;
②开始循环链表寻找目标元素,注意这里是通过cur.next.val来判断的;
③如果找到目标元素,就使用cur.next = cur.next.next;
④最后返回的时候要用dummyHead.next,而不是dummyHead。

Java代码:

public ListNode removeElements(ListNode head, int val) {
    ListNode dummyHead = new ListNode(0);
    dummyHead.next = head;
    ListNode cur = dummyHead;
    while(cur.next != null){
        if(cur.next.val == val)
            cur.next = cur.next.next;
        else
            cur = cur.next;
    }
    return dummyHead.next;
}

Python代码:

def removeElements(self, head, val):
    while head and head.val == val:
        head = head.next
    if head is None:
        return head
    node = head
    while node.next:
        if node.next.val == val:
            node.next = node.next.next
        else:
            node = node.next
    return head

C语言代码:

struct ListNode* removeElements(struct ListNode* head, int val) {
    struct ListNode* dummyHead = (struct ListNode* )malloc(sizeof(struct ListNode));
    dummyHead->val = 0;
    dummyHead->next = head;

    struct ListNode* cur = dummyHead;
    while(cur->next != NULL){
        if(cur->next->val == val){
            struct ListNode* temp = cur->next;
            cur->next = cur->next->next;
            free(temp);
        }
        else
            cur = cur->next;
    }
    
    return dummyHead->next;
}

Python代码(本地编辑器测试代码):

class ListNode(object):
    def __init__(self, val = None, next = None):
        self.val = val
        self.next = next

def init_list(nums):
    tem_node = ListNode()
    tem = ListNode()

    for i in nums:
        if tem_node.val == None:
            tem_node.val = i
            tem = tem_node
        else:
            tem_node.next = ListNode(i)
            tem_node = tem_node.next
    return tem

class RemoveElements:
    def removeElements(self, head, val):
        while head and head.val == val:
            head = head.next
        if head is None:
            return head
        node = head
        while node.next:
            if node.next.val == val:
                node.next = node.next.next
            else:
                node = node.next
        return head

def print_list(head):
    if not head or not head.next:
        return []
    result = []
    while head:
        result.append(head.val)
        head = head.next
    return result

if __name__ == "__main__":
    nums = [1, 2, 3, 4, 5, 6]
    n = int(input())
    list = init_list(nums)
    removeElements = RemoveElements()
    flag = removeElements.removeElements(list, n)
    print(print_list(flag))

10、删除倒数第n个结点

题目:LeetCode19
给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。
示例:
输入:head = [1,2,3,4,5], n = 2
输出:[1,2,3,5]
在这里插入图片描述

方法:双指针。定义fast和slow两个指针,fast先走N步,然后slow再开始走,当fast走到队尾的时候,slow就是我们要删除的结点。

Java代码:

public ListNode removeNthFromEnd(ListNode head, int n) {
   ListNode dummy = new ListNode(0);
   dummy.next = head;
   ListNode fast = head;
   ListNode slow = dummy;
   for(int i = 0; i < n; i ++){
       fast = fast.next;
   }
   while(fast != null){
       fast = fast.next;
       slow = slow.next;
   }
   slow.next = slow.next.next;
   return dummy.next;
}      

Python代码:

def removeNthFromEnd(self, head, n):
        
    dummy = ListNode(0, head)
    fast = head
    slow = dummy
    for i in range (1, n):
        fast = fast.next
    while(fast.next):
        fast = fast.next
        slow = slow.next
    
    slow.next = slow.next.next
    return dummy.next

C语言代码:

struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
    struct ListNode* dummy = (struct ListNode* )malloc(sizeof(struct ListNode));
    dummy->val = 0;
    dummy->next = head;
    struct ListNode* fast = head;
    struct ListNode* slow = dummy;
   
    for(int i = 0; i < n; i ++){
        fast = fast->next;
    }
    while(fast != NULL){
        fast = fast->next;
        slow = slow->next;
    }
    slow->next = slow->next->next;
    return dummy->next;

}

11、删除重复元素(重复元素保留一个)

题目:LeetCode83
给定一个已排序的链表的头 head ,删除所有重复的元素,使每个元素只出现一次。返回已排序的链表。
示例:
输入:head = [1,1,2]
输出:[1,2]
在这里插入图片描述

方法:从指针cur指向链表的头结点,随后开始对链表进行遍历。如果当前cur与cur对应的元素相同,那么我们就将cur.next从链表中移除;否则执行cur = cur.next;当遍历完整个链表之后,返回链表的头结点。

Java代码:

public ListNode deleteDuplicates(ListNode head) {
    if(head == null){
        return head;
    }
    ListNode cur = head;
    while(cur.next != null){
        if(cur.val == cur.next.val){
            cur.next = cur.next.next;
        }
        else{
            cur = cur.next;
        }
    }
    return head;
}

Python代码:

def deleteDuplicates(self, head):
    if not head:
        return head
    cur = head
    while cur.next:
        if cur.val == cur.next.val:
            cur.next = cur.next.next
        else:
            cur = cur.next
    return head

C语言代码:

struct ListNode* deleteDuplicates(struct ListNode* head) {
    if(head == NULL){
        return head;
    }
    //创建结点这么写
    //struct ListNode* cur = (struct ListNode* )malloc(sizeof(struct ListNode));
    //创建链表这么写
    struct ListNode* cur = head;
    
    while(cur->next != NULL){
        if(cur->val == cur->next->val){
            cur->next = cur->next->next;
        }
        else{
            cur = cur->next;
        }
    }
    return head;
}

Python代码(本地编辑器测试):

class ListNode(object):
    def __init__(self, val = None, next = None):
        self.val = val
        self.next = next

def init_list(nums):
    tem_node = ListNode()
    tem = ListNode()

    for i in nums:
        if tem_node.val == None:
            tem_node.val = i
            tem = tem_node
        else:
            tem_node.next = ListNode(i)
            tem_node = tem_node.next

    return tem

class DeleteDuplicates:
    def deleteDuplicates(self, head):
        if not head:
            return head
        cur = head
        while cur.next:
            if cur.val == cur.next.val:
                cur.next = cur.next.next
            else:
                cur = cur.next
        return head
#打印链表
def print_list(head):
    if not head or not head.next:
        return []
    result = []
    while head:
        result.append(head.val)
        head = head.next
    return result

if __name__ == "__main__":
    nums = [1, 1, 2, 3, 3]
    list = init_list(nums)
    deleteDuplicates = DeleteDuplicates()
    node = deleteDuplicates.deleteDuplicates(list)
    s = print_list(node)
    print(s)

12、删除重复元素(重复元素都不要)

题目:LeetCode82
给定一个已排序的链表的头 head ,删除原始链表中所有重复数字的节点,只留下不同的数字。返回已排序的链表。
示例:
输入:head = [1,2,3,3,4,4,5]
输出:[1,2,5]
在这里插入图片描述

方法:当一个都不要时,记下结点(cur.next)的val,把cur.next以及cur.next.next两个node与之相比较就行了。这里要注意两个node可能为空,要稍加判断。

Java代码:

public ListNode deleteDuplicates(ListNode head) {
    if(head == null){
        return head;
    }
    ListNode dummy = new ListNode(0,head);
    ListNode cur = dummy;
    //这里这样写是因为下面的if要判断cur.next.next.val
    while(cur.next != null && cur.next.next != null){   
        if(cur.next.val == cur.next.next.val){
            int x = cur.next.val;

            while(cur.next != null && cur.next.val == x){
                cur.next = cur.next.next;
            }

        }
        else{
            cur = cur.next;
        }
    }
    return dummy.next;
}

Python代码:

def deleteDuplicates(self, head):
    if not head:
        return head
    dummy = ListNode(0, head)
    cur = dummy
    while cur.next and cur.next.next:
        if cur.next.val == cur.next.next.val:
            x = cur.next.val
            while cur.next and cur.next.val == x:
                cur.next = cur.next.next
        else:
            cur = cur.next

    return dummy.next

C语言代码:

struct ListNode* deleteDuplicates(struct ListNode* head) {
    if(head == NULL){
        return head;
    }

    struct ListNode* dummy = (struct ListNode* )malloc(sizeof(struct ListNode));
    dummy->val = 0;
    dummy->next = head;
    struct ListNode* cur = dummy;

    while(cur->next != NULL && cur->next->next != NULL){
        if(cur->next->val == cur->next->next->val){
            int x = cur->next->val;
            while(cur->next != NULL && cur->next->val == x){
                struct ListNode* temp = cur->next;
                cur->next = cur->next->next;
                free(temp);
            }
        }
        else{
            cur = cur->next;
        }
    }

    return dummy->next;
}

本篇文章为原创文,欢迎转载,请注明文章出处https://blog.csdn.net/2301_79084755/article/details/136360792。技术类文章一般都有时效性,本人会不定期对自己的博客进行修正更新,因此请访问出处以查看本文的最新版本。

  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值