Leetcode初级总结(三)链表

链表的基本操作

1、创建一个单链表
  • 头插法(下面会用的到)
int createListHead(linkList *L,int n) {
    linkList p;
    int i = 0;
    srand((int)time(0));
    for (i = 0; i < n; i++)
    {
        p= (linkList)malloc(sizeof(Node));
        p->data = rand() % 100;
        printf("testing:Node[%d]=%d\n",i+1,p->data);
        p->next = (*L)->next;
        (*L)->next = p;
    }
    printf("链表(头插法)创建成功\n");
    return 1;
}
  • 尾插法
int createListTail(linkList *L, int n) {
    linkList p, temp;
    temp = (*L);
    int i;
    srand((int)time(0));
    for (i = 0; i < n;i++) {
        p = (linkList)malloc(sizeof(Node));
        p->data = rand() % 100;
        printf("testing:Node[%d]=%d\n", i + 1, p->data);
        p->next = NULL;
        temp->next = p;
        temp = p;
    }
    printf("链表(尾插法)创建成功\n");
    return 1;
}
2、插入节点
int insertList(linkList *L, int i, ElemType data)
{
    linkList p;
    linkList insNode;
    p = (*L);
    int j=0;
    // 链表为空,在第1个位置插入一个新的节点;
    if (p ->next == NULL) {
        printf("链表为空,默认在第一个位置插入一个节点.\n");
        insNode = (linkList)malloc(sizeof(Node));
        insNode->data = data;
        insNode->next = p->next;
        p->next = insNode;
        printf("节点插入成功.\n");
        return 1;
    }
    // 链表非空的情况下,可以在i=1~length的位置插入节点,如果超过了链表的长度,就会提示错误;
    // 其实如果在length+1的位置处插入一个新节点,就相当于在尾部追加一个节点,在本函数中会报错,可以单独实现一个函数;
    while(p && j<i-1) 
    {
        j++;
        p = p->next;
        //printf("j=%d\tp->data=%d\n", j, p->data);
    }
    if (p->next==NULL) {
        printf("您要插入的位置,超过了链表的长度 %d,请重新操作!\n",j);
        return 0;
    }
    insNode = (linkList)malloc(sizeof(Node));
    insNode->data = data;
    insNode->next = p->next;
    p->next = insNode;
    
    printf("节点插入成功\n");
    return 1;
}

Leetcode中链表的初级题目

1、删除链表中的节点
  • 题目描述

请编写一个函数,使其可以删除某个链表中给定的(非末尾)节点,你将只被给定要求被删除的节点。
说明:
链表至少包含两个节点。
链表中所有节点的值都是唯一的。
给定的节点为非末尾节点并且一定是链表中的一个有效节点。
不要从你的函数中返回任何结果。
示例1:
输入: head = [4,5,1,9], node = 5
输出: [4,1,9]
解释: 给定你链表中值为 5 的第二个节点,那么在调用了你的函数之后,该链表应变为 4 -> 1 -> 9.
示例2:
输入: head = [4,5,1,9], node = 1
输出: [4,5,9]
解释: 给定你链表中值为 1 的第三个节点,那么在调用了你的函数之后,该链表应变为 4 -> 5 -> 9.

  • 解题思路
    由于题目说明了被删除的节点不在末尾,并已经给出要删的节点node,可以将node值换成node的下个节点的值,将node的下一个指向node的下一个的下一个。
  • 代码
void deleteNode(struct ListNode* node) {
    if(!node || !node->next)
        return;

    node->val = node->next->val;
    node->next = node->next->next;
}
2、删除链表的倒数第N个节点
  • 题目描述
    给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。(说明:给定的n保证是有效的)
    示例:
    给定一个链表: 1->2->3->4->5, 和 n = 2.
    当删除了倒数第二个节点后,链表变为 1->2->3->5.
  • 解题思路
    使用双指针,让第一个指针先走n步,两个指针再同时向后移动,当第一个指针移动到链表的尾部时,第二个指针的位置指向待删节点的前一个。然后在考虑下特殊情况,比如链表为空,或者链表中只有一个元素。
  • 代码
struct ListNode* removeNthFromEnd(struct ListNode* head, int n) {
	if (n==0)
        return head;
    
    struct ListNode *fast=NULL, *slow=NULL, *p=NULL; //初始化为空
    fast = slow = head;
    for (int i=0; i<n; i++)
    {
        fast=fast->next;
    }
    
    while (fast) { 
        p=slow;
        fast=fast->next;
        slow=slow->next;
    }
    
    if(slow==head)
        head=head->next;
    else {
        p ->next = slow->next;
        free(slow);
    }
    return head;
    
}
3、反转链表
  • 题目描述
    反转一个单链表。
    示例:
    输入: 1->2->3->4->5->NULL
    输出: 5->4->3->2->1->NULL
  • 解题思路
    新建一个节点,不断取出和向后移动头结点,然后使用头插法将节点连接在新节点中。具体做法:将原先链表中的节点取出一个(取头结点,然后向后移一位),按照头插法的方式加到新的链中,取完所有的节点就完成了反转链表
  • 代码
struct ListNode* reverseList(struct ListNode* head) {
    struct ListNode *newHead=NULL, *next=NULL;
    while (head) {
        //单独取出下一个节点
        next = head->next;
        head->next = newHead;
        newHead = head;
        head = next;
    }
    return newHead;
}
4、合并两个有序链表
  • 题目描述
    将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
    示例:
    输入:1->2->4, 1->3->4
    输出:1->1->2->3->4->4
  • 解题思路
    定义一个新的链表存储合并后的结果,L1和L2都不为空的时候,将值小的元素依次加到新链表中,如果有一个为空了,就把另一个剩下的全部加到结果中。
  • 代码
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2) {
    
    struct ListNode *l3=(struct ListNode*)malloc(sizeof(struct ListNode));
    struct ListNode *p1,*p2,*p3;
    p1=l1;
    p2=l2;
    p3=l3;
    if(p1 == NULL) return p2;
    if(p2 == NULL) return p1;
        
    while(p1 !=NULL  && p2 !=NULL )
    {
        if(p1->val <= p2->val)
        {
            p3->next = p1;
            p3 = p3->next;
            p1 = p1->next;
            
        }
        else
        {
            p3->next =p2;
            p3 = p3->next;
            p2 = p2->next;
            
        }
    }
    if(p1 == NULL)
    {
        p3->next = p2;
    }
    else
    {
        p3->next = p1;
    }
    return l3->next;
    
    
}

5、回文链表
  • 题目描述
    请判断一个链表是否为回文链表。
    示例1:
    输入: 1->2
    输出: false
    示例2:
    输入: 1->2->2->1
    输出: true
  • 解题思路
    新建一个链表,用例存放反转后的链表,然后比较反转后的链表和原链表的节点值一样不,如果一样就说明是回文链表,正着和倒着一样;如果翻转后和原来的不一样,就说明不是回文链表
  • 代码
bool isPalindrome(struct ListNode* head) {
    struct ListNode *newHead=NULL, *q=head;
    struct ListNode* p;
    
    while(head) {
        p = (struct ListNode*)malloc(sizeof(struct ListNode));
        p->val=head->val;
        p->next=newHead;
        newHead=p;
        head=head->next;
    }
    
    while(q) {
        if(newHead->val!=q->val)
            return false;
        newHead=newHead->next;
        q=q->next;
    }
    return true;
}
6、环形链表
  • 题目描述
    给定一个链表,判断链表中是否有环。
    为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。
    示例1:
    输入:head = [3,2,0,-4], pos = 1
    输出:true
    解释:链表中有一个环,其尾部连接到第二个节点。
    示例2:
    输入:head = [1,2], pos = 0
    输出:true
    解释:链表中有一个环,其尾部连接到第一个节点。
    示例3:
    输入:head = [1], pos = -1
    输出:false
    解释:链表中没有环。
  • 解题思路
    使用两个指针:快指针和慢指针,快指针每次走两步,慢指针每次走一步,两个指针同时从头节点开始移动,如果快指针和慢指针的值相同了,就说明有环,否则没有环。
  • 代码
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;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值