LeetCode题目练习-链表

说明:第一个算法是迭代,第二个是递归

链表反转

Reverse a singly linked list.

Example:

Input: 1->2->3->4->5->NULL Output: 5->4->3->2->1->NULL Follow up:

A linked list can be reversed either iteratively or recursively. Could
you implement both?

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* reverseList1(struct ListNode* head) {//迭代 4ms 时间复杂度o(n)空间复杂度o(1)
	if (!head||!head->next) return head;
	struct ListNode* cur = head;
	struct ListNode* prev = NULL;
    struct ListNode* next = cur->next;
	while (next) {
		cur->next = prev;
        prev = cur;
        cur = next;
        next = next->next;
	}
    cur->next = prev;
	return cur;
}

struct ListNode* reverseList2(struct ListNode* head) {//递归 0ms 时间复杂度o(n)
    if (!head||!head->next) return head;
	struct ListNode *p = reverseList2(head->next);
	head->next->next = head;//为什么这里是next next?因为这样实际是给p赋值,p总是等于head->next
	head->next = NULL;
	return p;
}

链表两两反转

Given a linked list, swap every two adjacent nodes and return its
head.

You may not modify the values in the list’s nodes, only nodes itself
may be changed.

Example:

Given 1->2->3->4, you should return the list as 2->1->4->3.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* swapPair1(struct ListNode* head) {
    //执行用时 :4 ms
    if(head==NULL||head->next==NULL) return head;
    struct ListNode* thead =(struct ListNode*)malloc(sizeof(struct ListNode));
    thead->val = -1;
    thead->next = head;
    struct ListNode* s = thead;
    struct ListNode* a,*b;
    while((s->next) && (s->next->next)){
        a = s->next;
        b = s->next->next;
        s->next = b;
        a->next = b->next;
        b->next = a;
        s = a;//关键一步
    }
    return thead->next;
}

struct ListNode* swapPair2(struct ListNode* head) {
    if(!head||!head->next) return head;
    struct ListNode *t = head->next;
    struct ListNode *p = head->next->next;
    t->next = head;
    //以上已经实现了翻转相邻链表
    head->next = swapPair2(p);
    //head的后继节点显然要链接到每次递归后的开头节点,也就是返回的t节点【重点理解】
    return t;
    //这里只能return t,因为t是链表的开头节点,也是每次递归链表的开头节点
}

迭代算法说一下,参见某大佬的讲解
转自leetcode

链表判环※

Given a linked list, determine if it has a cycle in it.

To represent a cycle in the given linked list, we use an integer pos
which represents the position (0-indexed) in the linked list where
tail connects to. If pos is -1, then there is no cycle in the linked
list.

Example 1:

Input: head = [3,2,0,-4], pos = 1 Output: true Explanation: There is a
cycle in the linked list, where tail connects to the second node.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
bool hasCycle(struct ListNode *head) {
    if(!head||!head->next) return 0;
    struct ListNode *p = head;
    struct ListNode *fast = head;
    struct ListNode *slow = head;
    while (1){
        fast = fast->next->next;
        slow = slow->next;//快慢指针
        if(!fast||!fast->next) return 0;
        if(fast == slow) return 1;
    }
    //接下来的代码表示如何找到入环节点
    //定理:ptr1 指向链表的头, ptr2 指向相遇点。每次将它们往前移动一步,直到它们相遇,它们相遇的点就是环的入口。
    while(p != slow){
        p = p->next;
        slow = slow->next;
    }
    return p;
}
//C++使用set(最佳)
class Solution {
public:
    ListNode *detectCycle(ListNode *head) {
        unordered_set<ListNode *> st;
        while(!head){
        //count方法统计head出现多少次,次数大于1则返回入环节点
            if(st.count(head)) return head;
            st.insert(head);
            head=head->next;
        }
        return NULL;
    }
};

另:

  • 解法一:如果可破坏数据,将元素都修改为某指定值,从头遍历链表,如果遍历到顶说明无环,遍历到指定值说明有环;
  • 解法二:如果已知链表长度为N,从头遍历链表N次,如果遍历到顶说明无环,遍历顺利完成,说明未到顶,有环。或设定遍历时间为1s,1s内仍未遍历完说明有环。
发布了24 篇原创文章 · 获赞 12 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Protocols7/article/details/103836849