目录
Number 1:删除链表中等于给定值 val 的所有结点。
Number 2:反转一个单链表。
Number 3:给定一个带有头结点 head 的非空单链表,返回链表的中间结点。如果有两个中间结点,则 返回第二个中间结点。
Number 4: 输入一个链表,输出该链表中倒数第k个结点。
Number 5:将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有结点组成的。
Number 6:编写代码,以给定值x为基准将链表分割成两部分,所有小于x的结点排在大于或等于x的结点之前 。
Number 7:链表的回文结构。
Number 8:输入两个链表,找出它们的第一个公共结点。
Number 9:给定一个链表,判断链表中是否有环。
Number 10:给定一个链表,返回链表开始入环的第一个结点。 如果链表无环,则返回 NULL
203. 移除链表元素 - 力扣(LeetCode)https://leetcode.cn/problems/remove-linked-list-elements/description/
struct ListNode* removeElements(struct ListNode* head, int val) {
struct ListNode* cur = head;
struct ListNode* prev = NULL;
while (cur)
{
if (cur->val == val)
{
//头删
if (cur == head)
{
head = cur->next;
free(cur);
cur = head;
}
else
{
prev->next = cur->next;
free(cur);
cur = prev->next;
}
}
else
{
prev = cur;
cur = cur->next;
}
}
return head;
}
struct ListNode* removeElements(struct ListNode* head, int val){
struct ListNode* cur = head;
struct ListNode* tail = NULL;
head = NULL;
while (cur)
{
if (cur->val == val)
{
struct ListNode* del= cur;
cur = cur->next;
free(del);
}
else
{
if (tail == NULL)
{
head = tail = cur;
}
else
{
tail->next = cur;
tail = tail->next;
}
cur = cur->next;
}
}
if (tail != NULL)
{
tail->next = NULL;
}
return head;
}
struct ListNode* removeElements(struct ListNode* head, int val) {
struct ListNode* cur = head;
struct ListNode* tail = NULL;
head = tail = (struct ListNode*)malloc(sizeof(struct ListNode));
tail->next = NULL;
while (cur)
{
if (cur->val == val)
{
struct ListNode* del = cur;
cur = cur->next;
free(del);
}
else
{
tail->next = cur;
tail = tail->next;
cur = cur->next;
}
}
tail->next = NULL;
struct ListNode* del = head;
head = head->next;
free(del);
return head;
}
206. 反转链表 - 力扣(LeetCode)https://leetcode.cn/problems/reverse-linked-list/submissions/
struct ListNode* reverseList(struct ListNode* head){
struct ListNode* prev = NULL;
struct ListNode* next = NULL;
while (head != NULL)
{
next = head->next;
head->next = prev;
prev = head;
head = next;
}
return prev;
}
876. 链表的中间结点 - 力扣(LeetCode)https://leetcode.cn/problems/middle-of-the-linked-list/submissions/
struct ListNode* middleNode(struct ListNode* head){
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast != NULL && fast->next!=NULL)
{
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
struct ListNode* middleNode(struct ListNode* head) {
int count = 0;
int mid = 0;
struct ListNode* cur = head;
while (cur != NULL)
{
count++;
cur = cur->next;
}
mid = count / 2 + 1;
while (--mid)
{
head = head->next;
}
return head;
}
链表中倒数第k个结点_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId=13&&tqId=11167&rp=2&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking
struct ListNode* FindKthToTail(struct ListNode* pListHead, int k ) {
// write code here
struct ListNode* slow = pListHead;
struct ListNode* fast = pListHead;
//当fast提前走k步
while(k--)
{
if(fast == NULL)
return NULL;
fast = fast->next;
}
while(fast)
{
slow = slow->next;
fast = fast->next;
}
return slow;
}
21. 合并两个有序链表 - 力扣(LeetCode)https://leetcode.cn/problems/merge-two-sorted-lists/description/
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
if(list1 == NULL)
{
return list2;
}
if(list2 == NULL)
{
return list1;
}
struct ListNode* head = NULL;
struct ListNode* tail = NULL;
while(list1 && list2)
{
if(list1->val < list2->val)
{
if(tail == NULL)
{
head = tail = list1;
}
else
{
tail->next = list1;
tail =tail->next;
}
list1 = list1->next;
}
else
{
if(tail == NULL)
{
head = tail = list2;
}
else
{
tail->next = list2;
tail =tail->next;
}
list2 = list2->next;
}
}
if(list1 != NULL)
{
tail->next = list1;
}
if(list2 != NULL)
{
tail->next = list2;
}
return head;
}
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
struct ListNode* head = NULL;
struct ListNode* tail = NULL;
head = tail = (struct ListNode*)malloc(sizeof(struct ListNode));
tail->next = NULL;
while(list1 && list2)
{
if(list1->val < list2->val)
{
tail->next = list1;
tail =tail->next;
list1 = list1->next;
}
else
{
tail->next = list2;
tail =tail->next;
list2 = list2->next;
}
}
if(list1 != NULL)
{
tail->next = list1;
}
if(list2 != NULL)
{
tail->next = list2;
}
struct ListNode* del = head;
head = head ->next;
free(del);
return head;
}
链表分割_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/0e27e0b064de4eacac178676ef9c9d70?tpId=8&&tqId=11004&rp=2&ru=/activity/oj&qru=/ta/cracking-the-coding-interview/question-ranking
思路1:定义两个带有哨兵位的头结点,lesshead,greaterhead分别存储大小数据
同时使用两个指针lesstail、greatertail给给进行尾插,最后合并两个链表
lesstail->next = greaterhead;
返回合并链表的头结点,并且释放两个哨兵位结点
注意:
1.分析极端场景,脱离测试用例
2.分析,思考极端边界
3.第一个,都比x小,第二个,都比x大,第三个,有大有小
1.都比x大,此时lesshead->next = lesstail->next = NULL,此时,greatertail->next = NULL,而lesshead->next = lesstail->next = greaterhead->next 链接表时,不带哨兵位的头结点为greaterhead->next ,可以返回lesshead->next
2.都比x小,此时greaterhead->next = greatertail->next = NULL,此时,lesstail->next = NULL,而lesstail->next = greaterhead->next链接表时,不带哨兵位的头结点为lesshead->next,可以返回lesshead->next
4.有大有小,又分为两种情况,
第一种情况:geatertail最后比x大,greatertail->taill == NULL,此时lesstail->next 可以直接链接greaterhead
第二种情况:geatertail最后比x小,此时greatertail-> != NULL,此时会形成循环链表,因此此情况greatertail单链表尾必须要置为空
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class Partition {
public:
ListNode* partition(ListNode* pHead, int x) {
// write code here
struct ListNode* greaterhead, *greatertail, *lesshead, *lesstail;
greaterhead = greatertail = (struct ListNode*)malloc(sizeof(struct ListNode ));
lesshead = lesstail = (struct ListNode*)malloc(sizeof(struct ListNode ));
lesstail->next = NULL;
greaterhead ->next = NULL;
struct ListNode* cur = pHead;
while (cur) {
if (cur->val < x) {
lesstail->next = cur;
lesstail = lesstail->next;
} else {
greatertail->next = cur;
greatertail = greatertail->next;
}
cur = cur->next;
}
greatertail->next = NULL;
lesstail->next = greaterhead->next;
struct ListNode* head = lesshead->next;
free(greaterhead);
free(lesshead);
return head;
}
};
链表的回文结构_牛客题霸_牛客网 (nowcoder.com)https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId=49&&tqId=29370&rp=1&ru=/activity/oj&qru=/ta/2016test/question-ranking
对称就是回文
对于一个链表,请设计一个时间复杂度为O(n),额外空间复杂度为O(1)的算法,判断其是否为回文结构。
给定一个链表的头指针A,请返回一个bool值,代表其是否为回文结构。保证链表长度小于等于900。
通过查找中间结点,逆置,判断
class Solution {
public:
bool isPalindrome(ListNode* head) {
vector vals;
while (head != nullptr) {
vals.emplace_back(head->val);
head = head->next;
}
for (int i = 0, j = (int)vals.size() - 1; i < j; ++i, --j) {
if (vals[i] != vals[j]) {
return false;
}
}
return true;
}
};
/*
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};*/
class PalindromeList {
public:
struct ListNode* middleNode(struct ListNode* head) {
struct ListNode* slow = head;
struct ListNode* fast = head;
while (fast != NULL && fast->next != NULL) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
struct ListNode* reverseList(struct ListNode* head) {
struct ListNode* cur = head;
struct ListNode* prev = NULL;
struct ListNode* next = NULL;
while (head != NULL) {
next = head->next;
head->next = prev;
prev = head;
head = next;
}
return prev;
}
bool chkPalindrome(ListNode* A) {
struct ListNode* head = A;
struct ListNode* mid = middleNode(head);
struct ListNode* rhead = reverseList(mid);
while(head && rhead)
{
if(head->val != rhead->val)
{
return false;
}
else
{
head = head->next;
rhead = rhead->next;
}
}
return true;
}
};
160. 相交链表 - 力扣(LeetCode)https://leetcode.cn/problems/intersection-of-two-linked-lists/description/
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
struct ListNode *getIntersectionNode(struct ListNode *headA, struct ListNode *headB) {
if(headA == NULL || headB == NULL)
{
return NULL;
}
struct ListNode* curA = headA;
struct ListNode* curB = headB;
int lenA = 1;
int lenB = 1;
while(curA->next)
{
curA = curA->next;
lenA++;
}
while(curB->next)
{
curB = curB->next;
lenB++;
}
if(curA!=curB)
{
return NULL;
}
struct ListNode* shortList = headA,*longList = headB;
if(lenA>lenB)
{
shortList = headB;
longList = headA;
}
int gap = abs(lenA - lenB);
while(gap--)
{
longList = longList->next;
}
while(shortList != longList)
{
shortList = shortList->next;
longList = longList->next;
}
return shortList;
}
Loading Question... - 力扣(LeetCode)https://leetcode.cn/problems/linked-list-cycle/description/【思路】
快慢指针,即慢指针一次走一步,快指针一次走两步,两个指针从链表其实位置开始运行, 如果链表 带环则一定会在环中相遇,否则快指针率先走到链表的末尾。比如:陪女朋友到操场跑步减肥。
【扩展问题】
为什么快指针每次走两步,慢指针走一步可以?
假设链表带环,两个指针最后都会进入环,快指针先进环,慢指针后进环。
当慢指针刚进环时,可能就和快指针相遇了,最差情况下两个指针之间的距离刚好就是环的长度。
此时,两个指针每移动一次,之间的距离就缩小一步,不会出现每次刚好是套圈的情 况,因此:在满指针走到一圈之前,快指针肯定是可以追上慢指针的,即相遇。
快指针一次走3步,走4步,...n步行吗?
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/
bool hasCycle(struct ListNode *head) {
struct ListNode* fast =head,*slow=head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
return true;
}
}
return false;
}
142. 环形链表 II - 力扣(LeetCode)https://leetcode.cn/problems/linked-list-cycle-ii/description/结论:
让一个指针从链表起始位置开始遍历链表,同时让一个指针从判环时相遇点的位置开始绕环 运行,两个指针都是每次均走一步,最终肯定会在入口点的位置相遇。
证明:
struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode* fast =head,*slow=head;
while(fast && fast->next)
{
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
{
struct ListNode* meet = slow;
while(meet != head)
{
head = head->next;
meet = meet->next;
}
return meet;
}
}
return false;
}
链表OJ题目链接:
链表知识点题库 - 力扣(LeetCode)https://leetcode.cn/tag/linked-list/problemset/牛客网在线编程_编程学习|练习题_数据结构|系统设计题库 (nowcoder.com)https://www.nowcoder.com/exam/oj