数据结构Day9

不想你离开。 提交于 2020-03-09 13:45:57

1、删除链表的倒数第N个节点

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例: 给定一个链表: 1->2->3->4->5, 和 n = 2.当删除了倒数第二个节点后,链表变为 1->2->3->5.
说明: 给定的 n 保证是有效的。
进阶: 你能尝试使用一趟扫描实现吗?

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* removeNthFromEnd(struct ListNode* head, int n){
    struct ListNode *front = head, *temp = NULL;
    //设置两个指针变量,一个指向第n个节点,另一个保持头节点,
    //之后一直做循环,直到second节点指向了最后一个节点时,
    //此时first节点就会指向倒数第n个节点,之后对该节点做删除操作即可。
    struct ListNode *first = head, *second = head;
    int ntemp = n;
    while(n)
    {
        if(second->next != NULL)
        {
            second = second->next;
        }
        else
        {
            return (ntemp == 1) ? NULL : front->next;
        }
        n--;
    }
    while(second != NULL)
    {
        temp = first;
        first = first->next;
        second = second->next;
    }
    temp->next = first->next;
    return front;
}

在这里插入图片描述
总结 : 最近这段时间太忙了,今天终于有时间可以坐下来继续我的学习之旅,感觉要开心许多了,首先通过一个链表的中等题目作为回顾链表知识吧。
拿到这个题目的第一个想法就是得出链表的长度,之后用删除第L-n-1个节点即可,但是题目中要求只遍历一次链表。这个题目中非常巧妙的运用了双指针的形式,从而实现时间复杂度为O(n),同时只遍历了一遍链表。具体的实现方法为,设置两个指针变量,一个指向第n个节点,另一个保持头节点,之后一直做循环,直到second节点指向了最后一个节点时,此时first节点就会指向倒数第n个节点,之后对该节点做删除操作即可。之后对链表中可能出现了边缘进行保护,即在用second遍历的时候判断n个节点之后是否会到链表尾部,如果是的话再次进行判断链表是否只有一个节点,这种情况下则需返回NULL,否则的话返回front->next就可以了。

2、合并两个有序链表

将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    if (!l1)
		return l2;
	if (!l2)
		return l1;

    struct ListNode *result = (struct ListNode *)malloc(sizeof(struct ListNode));
    struct ListNode *front = result;

    while( l1  && l2)
    {
        if(l1->val > l2->val)
        {
            result->next = l2;
            l2 = l2->next;
        }
        else
        {
            result->next = l1;
            l1 = l1->next;
        }
        result = result->next;
    }

    for(;l1;l1 = l1->next)  
    {
        result->next = l1;
        result = result->next;
    }
    for(;l2;l2 = l2->next)
    {
        result->next = l2;
        result = result->next;
    }
    return front->next;
}

在这里插入图片描述
总结 在这个题目中,有序链表的排序的逻辑不是很复杂,关键是如何避免内存溢出,指针跑飞的情况,最后在两个链表中有一个链表的值已经到头之后,用两个for循环赋值的操作可以做如下优化:

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode* l1, struct ListNode* l2){
    if (!l1)
		return l2;
	if (!l2)
		return l1;
    struct ListNode *result = (struct ListNode *)malloc(sizeof(struct ListNode));
    struct ListNode *front = result;
    while( l1  && l2)
    {
        if(l1->val > l2->val)
        {
            result->next = l2;
            l2 = l2->next;
        }
        else
        {
            result->next = l1;
            l1 = l1->next;
        }
        result = result->next;
    }
    if(l1)  result->next = l1;
    else if(l2)     result->next = l2;
    return front->next;
}

在这里插入图片描述
最后的结果可以看到有了很大的提高。得,又有事情要忙了,再见。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!