0
点赞
收藏
分享

微信扫一扫

链表力扣题解(上)

目录

单链无头无循环链表的基本:

1:反转链表

2:移除链表元素(快慢指针)

3:合并两个有序链表(双指针)

4:环形链表|(快慢指针)

5:环形链表||(快慢指针+简单数学)

6:相交链表(双指针)

7:删除链表的倒数第N个节点(快慢指针)

8:奇偶链表

9:回文链表(快慢指针)

力扣的双指针模板:


单链无头无循环链表的基本:

(1)链表的结构体:

(2)定义指针指向:

(3)指向下一个地址

(4)指向该地址所存储的值


1:反转链表

思路解析:

 结束条件:

画图解释:

 如图所示:当n2为最后一个节点时,是最后一个步骤

所以迭代条件是n2!=NULL

至于为什么是用三个指针,因为:n2->next=n1

会导致n2找到不到它在原链表的下一个节点,无法进行迭代

代码实现:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/



struct ListNode* reverseList(struct ListNode* head){
if (head == NULL)
{
return NULL;
}
struct ListNode* n1 = NULL;
struct ListNode* n2 = head;
struct ListNode* n3 = n2->next;

while (n2)
{
n2->next = n1;
n1 = n2;
n2 = n3;
if (n3)
{
n3 = n3->next;
}
}
return n1;
}

2:移除链表元素(快慢指针)

 思路解析:

 代码实现:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/



struct ListNode* removeElements(struct ListNode* head, int val){
while (head != NULL && head->val == val) {
head = head->next;//防止链表都是同一个元素的情况
}

struct ListNode* cur = head; // 当前节点
struct ListNode* pre = head; // 保存待删除节点的前一节点
while (cur != NULL) {
if (cur->val == val) {
pre->next = cur->next;
}
else {
pre = cur;
}
cur = cur->next;
}

return head;
}

3:合并两个有序链表(双指针)

 思路解析:

 代码实现:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/



struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
if(l1==NULL) return l2;
if(l2==NULL) return l1;
struct ListNode *head=NULL,*tail=NULL;
head=tail=(struct ListNode*)malloc(sizeof(struct ListNode));
while(l1!=NULL NULL)
{
if(l1->val < l2->val)
{
tail->next=l1;
l1=l1->next;
}
else
{
tail->next=l2;
l2=l2->next;
}
tail=tail->next;
}
if(l1!=NULL) tail->next=l1;
if(l2!=NULL) tail->next=l2;
head=head->next;//易错!!!!!

return head;
}

易错:因为head和tail初始化时时同一个空间,而后tail作为尾,尾插数据,head作为头不变,head本身不存储任何数据,所以其相当于一开始的tail,那么让head=head->next即tail尾插的第一个数据的节点,即head指向第一个节点的地址


4:环形链表|(快慢指针)

 思路解析:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/

bool hasCycle(struct ListNode *head) {
struct ListNode *slow=head,*fast=head;
while(fast && fast->next)
{
slow=slow->next;
fast=fast->next->next;
if(slow==fast) return true;
}
return false;
}

5:环形链表||(快慢指针+简单数学)

 思路解析:

代码实现:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/

struct ListNode *detectCycle(struct ListNode *head) {
struct ListNode*slow=head,*fast=head;
while(fast && fast->next)
{
slow=slow->next;
fast=fast->next->next;

if(slow==fast)
{
struct ListNode*meet=slow;//相遇点指针
while(head!=meet)
{
head=head->next;//头指针
meet=meet->next;
}
return meet;//出循环证明head==meet,该地址就是环入口
}
}
return NULL;
}

6:相交链表(双指针)

 

 思路解析:

 代码实现:

/**
* 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 *pA = headA, *pB = headB;
while (pA != pB) {
pA = pA == NULL ? headB : pA->next;
pB = pB == NULL ? headA : pB->next;
}
return pA;
}

可以自己用两个手指进行模拟,非常巧妙^ ^


7:删除链表的倒数第N个节点(快慢指针)

 思路解析:

我们这里先给出删除链表的正数第N个节点的代码:

struct ListNode* cur = head;  //  当前节点
struct ListNode* pre = head; // 保存待删除节点的前一节点
int i=0;
while (cur != NULL ) {
if (i==n-1) {
pre->next = cur->next;
}
else {
pre = cur;
}
cur = cur->next;
i++;
}

思路解析:

 本题的笨方法:

本题的巧方法:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/

struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
struct ListNode* slow = head;
struct ListNode* fast = head;

for (int i = 0; i < n; i++) fast = fast->next;
while (fast != NULL && fast->next != NULL)
{
slow = slow->next;
fast = fast->next;
}
if (fast == NULL) return head->next;
else slow->next = (slow->next)->next;

return head;
}

8:奇偶链表

 思路解析:

 代码实现:

/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* struct ListNode *next;
* };
*/


struct ListNode* oddEvenList(struct ListNode* head){
if (head == NULL) return head;
struct ListNode* evenHead = head->next;
struct ListNode* odd = head;
struct ListNode* even = evenHead;//初始化
while (even != NULL && even->next != NULL)//迭代条件
{
odd->next = even->next;//迭代过程
odd = odd->next;
even->next = odd->next;
even = even->next;
}
odd->next = evenHead;//链接
return head;
}

9:回文链表(快慢指针)

 思路解析:

bool isPalindrome(struct ListNode* head) {
int vals[50001], vals_num = 0;
while (head != NULL) {
vals[vals_num++] = head->val;
head = head->next;
}
for (int i = 0, j = vals_num - 1; i < j; ++i, --j) {
if (vals[i] != vals[j]) {
return false;
}
}
return true;
}

 有点点小难……………………

struct ListNode* reverseList(struct ListNode* head) {//反转链表
struct ListNode* prev = NULL;
struct ListNode* curr = head;
while (curr != NULL) {
struct ListNode* nextTemp = curr->next;//类似于swap函数
curr->next = prev;
prev = curr;
curr = nextTemp;//加了一个类似与i++的迭代,使得链表向前遍历
}
return prev;
}

struct ListNode* endOfFirstHalf(struct ListNode* head) {//快慢指针找中间结点
struct ListNode* fast = head;
struct ListNode* slow = head;
while (fast->next != NULL && fast->next->next != NULL) {//奇偶情况都要考虑
fast = fast->next->next;
slow = slow->next;
}
return slow;
}

bool isPalindrome(struct ListNode* head) {
if (head == NULL) {
return true;
}

// 找到前半部分链表的尾节点并反转后半部分链表
struct ListNode* firstHalfEnd = endOfFirstHalf(head);//前半部分
struct ListNode* secondHalfStart = reverseList(firstHalfEnd->next);//后半部分=后半部分的反转-注意传的是中间的下一个结点的地址

// 判断是否回文
struct ListNode* p1 = head;
struct ListNode* p2 = secondHalfStart;
bool result = true;
while (result NULL) {//两个链表正序判断
if (p1->val != p2->val) {//正序判断值是否相等->回文
result = false;
}
p1 = p1->next;//迭代
p2 = p2->next;
}

// 还原链表并返回结果
firstHalfEnd->next = reverseList(secondHalfStart);
return result;
}

此题用递归更为简单,以后看看悟了的话就出递归版的= =


力扣的双指针模板:

// Initialize slow & fast pointers
ListNode* slow = head;
ListNode* fast = head;
/**
* Change this condition to fit specific problem.
* Attention: remember to avoid null-pointer error
**/

while (slow && fast && fast->next) {
slow = slow->next; // move slow pointer one step each time
fast = fast->next->next; // move fast pointer two steps each time
if (slow == fast) { // change this condition to fit specific problem
return true;
}
}
return false; // change return value to fit specific problem

主要注意整个while的条件判断,因为要考虑到只有一个结点的情况

举报

相关推荐

0 条评论