链表刷题记录

1、从尾到头打印链表

牛客网练习题:原题链接
在这里插入图片描述
解题思路:
首先,用一个指针p代替头结点,然后遍历一遍链表,得到最后的链表大小,得到链表大小之后,再用--num来填充数组。注意:给出的是一个头结点。注释掉 第二个 p=listNode;则失败。这里说明这个头结点非常重要。

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 *
 * C语言声明定义全局变量请加上static,防止重复定义
 */
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param listNode ListNode类 
 * @return int整型一维数组
 * @return int* returnSize 返回数组行数
 */
int* printListFromTailToHead(struct ListNode* listNode, int* returnSize ) {
    // write code here
//********************************************一个头结点是多么重要~!~!~!~!~
    if(listNode == NULL)
        return -1;
    struct ListNode *p = listNode;
    int num = 0;
    int *res = NULL;
    while(p){
        p = p->next;
        num++;
    }

    res = (int *)malloc(num*sizeof(int));
    p = listNode;
    *returnSize = num;
    while(p){
        res[--num] = p->val;
        p = p->next;
    }
    return res;
}

方法2:尾部头插,此方法为取结点下来头插,不在原链表上反转

struct ListNode* reverseList(struct ListNode* head)
{

	struct ListNode* cur = head;
	struct ListNode* newhead = NULL;

	while (cur)
	{
		//即不断取结点下来,头插到NULL前面去
		struct ListNode* next = cur->next;
		
		cur->next = newhead;

		newhead = cur;

		cur = next;

	}
	return newhead;
}

2、反转链表,和上一题要求输出结果一样。

在这里插入图片描述
方法:

struct ListNode* reverseList(struct ListNode* head)
{

	struct ListNode* cur = head;
	struct ListNode* newhead = NULL;

	while (cur)
	{
		//即不断取结点下来,头插到NULL前面去
		struct ListNode* next = cur->next;
		
		cur->next = newhead;

		newhead = cur;

		cur = next;

	}
	return newhead;
}

3、JZ25 合并两个排序的链表

原题链接

在这里插入图片描述解答:

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 *
 * C语言声明定义全局变量请加上static,防止重复定义
 */

/**
 * 
 * @param pHead1 ListNode类 
 * @param pHead2 ListNode类 
 * @return ListNode类
 */
struct ListNode* Merge(struct ListNode* pHead1, struct ListNode* pHead2 ) {
    // write code here

    //创建虚拟头节点,虚拟头节点的next指向合并完成的链表
    struct ListNode *newNode = (struct ListNode *)malloc(sizeof(struct ListNode)),*node;
    
    node = newNode;
    
    while(pHead1 && pHead2){
        if(pHead1->val <= pHead2->val){
            node->next = pHead1;
            node = node->next;
            pHead1 = pHead1->next;   
        }
        else{
            node->next = pHead2;
            node = node->next;
            pHead2 = pHead2->next;
        }
    }
    node->next = pHead1 == NULL?pHead2:pHead1;//尾巴处理
    return newNode->next;
}

4、JZ18 删除链表的节点

在这里插入图片描述

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 *
 * C语言声明定义全局变量请加上static,防止重复定义
 */
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param head ListNode类 
 * @param val int整型 
 * @return ListNode类
 */
struct ListNode* deleteNode(struct ListNode* head, int val ) {
    // write code here
    if(head->val == val)return head->next;
    struct ListNode* prev  = head;
    struct ListNode* cur = head->next;
    while(cur){
        if(cur->val == val){
            prev->next = cur->next;
            break;
        }else{
            prev = cur;
            cur = cur->next;
        }
    }
    return head;
}

5、JZ52 两个链表的第一个公共结点

在这里插入图片描述

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 *
 * C语言声明定义全局变量请加上static,防止重复定义
 */

/**
 * 
 * @param pHead1 ListNode类 
 * @param pHead2 ListNode类 
 * @return ListNode类
 */
struct ListNode* FindFirstCommonNode(struct ListNode* pHead1, struct ListNode* pHead2 ) {
    // write code here
    struct ListNode* p = pHead1;
    struct ListNode* q = pHead2;
    while(p){
        while(q){
            if(p == q)
                return p;
                q = q->next;
        }
        p = p->next;
        q = pHead2;
    }
    return p;
}

6、链表的中间节点

原题链接

在这里插入图片描述利用快慢指针遍历链表,停下来的时候,慢指针所指向的结点就是中间结点

快慢指针的思想:

`本质`:为了解决“先让一个指针遍历一次链表得出链表的长度,继而再遍历一次去中间位置”的连次循环问题,提出了快慢指针的一次循环即可解决问题的办法

快慢指针前进的方向相同,且它们步伐的差是恒定的【即快指针的速度是慢指针的两倍】

所以当快指针走到最后一个结点的时候,慢指针刚好到中间结点

    1️⃣快指针:一次走两步

    2️⃣慢指针:一次走一步
struct ListNode* middleNode(struct ListNode* head)
{
	struct ListNode* fast = head;
	struct ListNode* slow = head;

	while (fast != NULL && fast->next != NULL)
	{
		slow = slow->next;
		fast = fast->next->next;
	}

	return slow;
}

7、JZ22 链表中倒数最后k个结点

在这里插入图片描述
同样利用与上题思想相同的快慢指针。

思路: 快慢指针

返回倒数第K个结点,即返回正数第总长度-K个结点

在不知道总长度的情况如何下,如何走总长度-K步?

1️⃣可以先让fast指针走K步,那此时fast指针离最后一个结点的距离就是总长度-K
2️⃣再让slow指针在第一个结点位置出发,fast走一步,slow走一步,同时前进,都走了总长度-K
3️⃣这样,当fast走到空的时候,slow指针指向的就是正数第总长度-K个结点,即倒数第K个结点

❗综上:

相当于让fast指针作一个计数器,先走K步,作slow指针的导向,指引其走总长度-K步,找到倒数第K个结点

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 *
 * C语言声明定义全局变量请加上static,防止重复定义
 */
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param pHead ListNode类 
 * @param k int整型 
 * @return ListNode类
 */
struct ListNode* FindKthToTail(struct ListNode* pHead, int k ) {
    // write code here
    struct ListNode* fast = pHead;
    struct ListNode* slow = pHead;
    
    while(k--){
        if(fast == NULL){
            return NULL;
        }
        fast = fast->next;
    }
    while(fast){
        slow = slow->next;
        fast = fast->next;
    }
    return slow;
}

8、分割链表

原题链接
在这里插入图片描述

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


struct ListNode* partition(struct ListNode* head, int x){
    
    struct ListNode* small = malloc(sizeof(struct ListNode));
    struct ListNode* smallHead = small;
    struct ListNode* large = malloc(sizeof(struct ListNode));
    struct ListNode* largeHead = large;
    while (head != NULL) {
        if (head->val < x) {
            small->next = head;
            small = small->next;
        } else {
            large->next = head;
            large = large->next;
        }
        head = head->next;
    }
    large->next = NULL;
    small->next = largeHead->next;
    
    return smallHead->next;
}

9、回文链表

原题链接

在这里插入图片描述

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


bool isPalindrome(struct ListNode* head){
    int len = 0;
    int i = 0;
    char arr[100000];
    int flag = 0;
    struct ListNode* cur = head;
    while(cur){
        arr[i++]=cur->val;
        cur = cur->next;
    }
    len = strlen(arr);
    for(i = 0;i < len/2;i++){
        if(arr[i] == arr[len-i-1])
            flag = true;
        else flag = false;
    }

    return flag;
}

样例通过了53个,这个没通过。
在这里插入图片描述官方答案:

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;

}

JZ23 链表中环的入口结点 (快慢指针)

在这里插入图片描述

解答:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述

代码实现:

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 *
 * C语言声明定义全局变量请加上static,防止重复定义
 */
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param pHead ListNode类 
 * @return ListNode类
 */
struct ListNode* EntryNodeOfLoop(struct ListNode* pHead ) {
    // write code here
    struct ListNode *fast = pHead;
    struct ListNode *slow = pHead;
    struct ListNode *newHead = pHead;
    while(fast && fast->next){
        fast = fast->next->next;
        slow = slow->next;
        if(slow == fast){
            struct ListNode *index1 = fast;
            struct ListNode *index2 = pHead;
            while(index1!=index2){
                index1 = index1->next;
                index2 = index2->next;
            }
            return index2;
        }
    }
    return NULL;
}

JZ76 删除链表中重复的结点

在这里插入图片描述

/**
 * struct ListNode {
 *	int val;
 *	struct ListNode *next;
 * };
 *
 * C语言声明定义全局变量请加上static,防止重复定义
 */
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 * 
 * @param pHead ListNode类 
 * @return ListNode类
 */
struct ListNode* deleteDuplication(struct ListNode* pHead ) {
    // write code here
    struct ListNode* newHead = (struct ListNode*)malloc(sizeof(struct ListNode));
    newHead->next = pHead;
    struct ListNode* pre,*cur;
    pre = newHead;
    cur = pHead;
    while(cur){
        if(cur->next && cur->val == cur->next->val){
            cur = cur->next;
            while(cur->next && cur->val == cur->next->val){
                cur = cur->next;
            }
            cur = cur->next;
            pre->next = cur;
        }
        else if(!cur->next || cur->val != cur->next->val){
            pre = cur;
            cur = cur->next;
        }
    }
    return newHead->next;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值