说明:第一个算法是迭代,第二个是递归
链表反转
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是链表的开头节点,也是每次递归链表的开头节点
}
迭代算法说一下,参见某大佬的讲解
链表判环※
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内仍未遍历完说明有环。