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 && l2!=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 && p2 != 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 条评论