数据结构与算法⑤(第二章OJ题,上)前五道链表面试题(下)

简介: 数据结构与算法⑤(第二章OJ题,上)前五道链表面试题

数据结构与算法⑤(第二章OJ题,上)前五道链表面试题(上):https://developer.aliyun.com/article/1513343

普通思路的代码:

struct ListNode* middleNode(struct ListNode* head){
    struct ListNode*cur=head;
    int count=0;
    while(cur!=NULL)
    {
        cur=cur->next;
        count++;//计算链表长度
    }
    struct ListNode*middle=head;
    for(int i=0;i<count/2;i++)//如5的话3次,6的话4次
    {
        middle=middle->next;
    }
    return middle;
}

这样的时间复杂度是N+N/2 虽然还是O(N)

但是以后面试可能会要求只能遍历一遍数组呢,这时就要用到快慢指针的思想了

虽然以前有用过,但是变一下就想不到了,看到这个思路又是震惊的一天...

运用快慢指针的代码:

struct ListNode* middleNode(struct ListNode* head) {
    struct ListNode* fast = head , * slow = head;
    while (fast!=NULL&&fast->next!=NULL)
    {
        fast=fast->next->next;//快指针一次走两步
        slow=slow->next;//慢指针一次走一步
    }
    return slow;
}

4. 输出该链表中倒数第k个结点

剑指 Offer 22. 链表中倒数第k个节点

输入一个链表,输出该链表中倒数第k个节点。为了符合大多数人的习惯,

本题从1开始计数,即链表的尾节点是倒数第1个节点。

例如,一个链表有 6 个节点,从头节点开始,它们的值依次是 1、2、3、4、5、6。

这个链表的倒数第 3 个节点是值为 4 的节点。

示例:

给定一个链表: 1->2->3->4->5, 和 k = 2.

返回链表 4->5.

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* getKthFromEnd(struct ListNode* head, int k){
 
}

(这题没给范围,有点不严谨,但是懂思路就好了)

力扣这题是后更新的,所以测试用例更不严谨

这里说一下,力扣应该是OJ题做的最好的,但是面试那些应该用牛客多一点。

牛客网链接:https://www.nowcoder.com/practice/529d3ae5a407492994ad2a246518148a?tpId=13&&tqId=11167&rp=2&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking

普通思路的代码:

这题和上一题的普通思路一样,相当于遍历两次链表

struct ListNode* getKthFromEnd(struct ListNode* head, int k){
    struct ListNode*cur=head;
    int count=0;
    while(cur!=NULL)
    {
        cur=cur->next;
        count++;//计算链表长度
    }
    struct ListNode*newHead=head;
    for(int i=0;i<count-k;i++)
    {
        newHead=newHead->next;
    }
    return newHead;
}

写完普通思路我想着用快慢指针怎么用,想了几秒就觉得不行就不想了,以为不能用

(不想动太多脑的坏处)看到别人的思路我已经开始咬嘴唇了...


虽然觉得k不一样时,时间一样,但是帅就对了:

运用快慢指针的代码:

struct ListNode* getKthFromEnd(struct ListNode* head, int k){
    struct ListNode* fast = head , * slow = head;
    while(k--)
    {
        if(fast==NULL)
        {
            return NULL;
        }
        fast=fast->next;//快指针先走k步
    }
    while(fast)
    {
        fast=fast->next;
        slow=slow->next;//快慢指针一起走
    }
    return slow;
}

5. 合并两个有序链表为一个新的有序链表

21. 合并两个有序链表

难度简单

将两个升序链表合并为一个新的 升序 链表并返回。

新链表是通过拼接给定的两个链表的所有节点组成的。

示例 1:



输入:l1 = [1,2,4], l2 = [1,3,4]

输出:[1,1,2,3,4,4]

示例 2:

输入:l1 = [], l2 = []

输出:[]

示例 3:

输入:l1 = [], l2 = [0]

输出:[0]

提示:

  • 两个链表的节点数目范围是 [0, 50]
  • -100 <= Node.val <= 100
  • l1 和 l2 均按 非递减顺序 排列
/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     struct ListNode *next;
 * };
 */
struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2){
 
}

尾插法代码:

 struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
     if (list1 == NULL)
     {
         return list2;
     }
     if (list2 == NULL)
     {
         return list1;
     }
     struct ListNode* cur=NULL;
     if(list1->val <= list2->val)
     {
        cur = list1;
        list1 = list1->next;
     }
     else
     {
        cur = list2;
        list2 = list2->next;
     }
     struct ListNode* new = cur;
     while (list1 && list2)
     {
         if (list1->val <= list2->val)
         {
             cur->next = list1;
             cur = list1;
             list1 = list1->next;
         }
         else
         {
             cur->next = list2;
             cur = list2;
             list2 = list2->next;
         }
     }
     if (list1 == NULL)
     {
         cur->next = list2;
     }
     else
     {
         cur->next = list1;
     }
     return new;
}

尾插法+哨兵位的头节点代码:

哨兵位的头节点就是不存数据的节点

 struct ListNode* mergeTwoLists(struct ListNode* list1, struct ListNode* list2) {
     if (list1 == NULL)
     {
         return list2;
     }
     if (list2 == NULL)
     {
         return list1;
     }
     struct ListNode* cur = (struct ListNode*)malloc(sizeof(struct ListNode));
     struct ListNode* new = cur;
     while (list1 && list2)
     {
         if (list1->val <= list2->val)
         {
             cur->next = list1;
             cur = list1;
             list1 = list1->next;
         }
         else
         {
             cur->next = list2;
             cur = list2;
             list2 = list2->next;
         }
     }
     if (list1 == NULL)
     {
         cur->next = list2;
     }
     else
     {
         cur->next = list1;
     }
     struct ListNode* newHead = new->next;
     free(new);
     return newHead;
}

本篇完。

后面还有接着这部分的较难的OJ题

目录
相关文章
|
6月前
|
机器学习/深度学习 算法
24. 两两交换链表中的节点, 19.删除链表的倒数第N个节点 ,面试题 02.07. 链表相交
1. **两两交换链表中的节点**:通过引入虚拟头结点,使所有节点都能采用统一的交换逻辑,避免对头结点单独处理。 2. **删除链表的倒数第N个节点**:利用双指针技巧,让快慢指针保持N个节点的距离,当快指针到达末尾时,慢指针正好指向待删除节点的前一个节点。 3. **链表相交**:先计算两链表长度并调整起点,确保从相同距离末尾的位置开始遍历,从而高效找到相交节点或确定无交点。 以上方法均在时间复杂度和空间复杂度上进行了优化,适合用于理解和掌握链表的基本操作及常见算法设计思路。
|
8月前
|
存储 算法 物联网
解析局域网内控制电脑机制:基于 Go 语言链表算法的隐秘通信技术探究
数字化办公与物联网蓬勃发展的时代背景下,局域网内计算机控制已成为提升工作效率、达成设备协同管理的重要途径。无论是企业远程办公时的设备统一调度,还是智能家居系统中多设备间的联动控制,高效的数据传输与管理机制均构成实现局域网内计算机控制功能的核心要素。本文将深入探究 Go 语言中的链表数据结构,剖析其在局域网内计算机控制过程中,如何达成数据的有序存储与高效传输,并通过完整的 Go 语言代码示例展示其应用流程。
147 0
|
10月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
386 30
|
10月前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
461 25
|
算法 安全 搜索推荐
2024重生之回溯数据结构与算法系列学习之单双链表精题详解(9)【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构王道第2.3章之IKUN和I原达人之数据结构与算法系列学习x单双链表精题详解、数据结构、C++、排序算法、java、动态规划你个小黑子;这都学不会;能不能不要给我家鸽鸽丢脸啊~除了会黑我家鸽鸽还会干嘛?!!!
|
存储 Web App开发 算法
2024重生之回溯数据结构与算法系列学习之单双链表【无论是王道考研人还是IKUN都能包会的;不然别给我家鸽鸽丢脸好嘛?】
数据结构之单双链表按位、值查找;[前后]插入;删除指定节点;求表长、静态链表等代码及具体思路详解步骤;举例说明、注意点及常见报错问题所对应的解决方法
|
存储 缓存 算法
经典算法之链表篇(三)
经典算法之链表篇(三)
211 4
|
存储 算法
非递归实现后序遍历时,如何避免栈溢出?
后序遍历的递归实现和非递归实现各有优缺点,在实际应用中需要根据具体的问题需求、二叉树的特点以及性能和空间的限制等因素来选择合适的实现方式。
298 59
|
6月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
131 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。

热门文章

最新文章