文章目录

  • 一、编程题:707. 设计链表(双向链表-带头尾双结点)
    • 1.题目描述
    • 2.示例1:
    • 3.提示:
  • 二、解题思路
    • 1.思路
    • 2.复杂度分析:
    • 3.算法图解(双向链表)
  • 三、代码实现
  • 三、单向链表代码实现
  • 总结

一、编程题:707. 设计链表(双向链表-带头尾双结点)

1.题目描述

  设计链表的实现。您可以选择使用单链表或双链表。单链表中的节点应该具有两个属性:val 和 next。val 是当前节点的值,next 是指向下一个节点的指针/引用。如果要使用双向链表,则还需要一个属性 prev 以指示链表中的上一个节点。假设链表中的所有节点都是 0-index 的。LeetCode题目链接。
  在链表类中实现这些功能:

  • get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。
  • addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。
  • addAtTail(val):将值为 val 的节点追加到链表的最后一个元素。
  • addAtIndex(index,val):在链表中的第 index 个节点之前添加值为 val 的节点。如果 index 等于链表的长度,则该节点将附加到链表的末尾。如果 index 大于链表长度,则不会插入节点。如果index小于0,则在头部插入节点。
  • deleteAtIndex(index):如果索引 index 有效,则删除链表中的第 index 个节点。

2.示例1:

MyLinkedList linkedList = new MyLinkedList();
linkedList.addAtHead(1);
linkedList.addAtTail(3);
linkedList.addAtIndex(1,2); //链表变为1-> 2-> 3
linkedList.get(1); //返回2
linkedList.deleteAtIndex(1); //现在链表是1-> 3
linkedList.get(1); //返回3

3.提示:

  • 0 <= index, val <= 1000
  • 请不要使用内置的 LinkedList 库。
  • get, addAtHead, addAtTail, addAtIndex 和 deleteAtIndex 的操作次数不超过 2000。

二、解题思路

  本题单纯就是对数据结构链表构成的考察,由于题中涉及到一些对中间变量的操作,所以采用双向链表来进行解决,加上贪心算法来进行查询位置加快运行速度。不过这里关键点还是在于要定义好链表的边界,这一点要理清楚。不然在编写过程容易缺失部分数据处理(本人踩的坑)。基本上能完成双向链表之后都可以写顺利写单向链表,不然也可以先写出单向链表,然后在写根据单向写双向,多写几遍印象更深刻点。

1.思路

解决方法1(个人想法):

  • Step 1.创建双向链表结点(有前驱后继),在MyLinkedList中创建头尾双结点,以便后续方便处理中间变量;
  • Step 2.涉及index操作时,采用贪心算法使其从最近的一边开始遍历(注:一定要对index进行安全处理,以防数据无效);
  • Step 3.编写Nodeshow函数打印链表数据,以便编写过程中进行调试;

2.复杂度分析:

时间复杂度:涉及 index 的相关操作复杂度为 O(index);其余操作均为 O(1)
空间复杂度:O(n)

3.算法图解(双向链表)

红色部分代表待操作元素。(注:本人不会做成流程动画,希望会的朋友可以私信我指点一二,说个软件名字也可以,谢谢
头插法(尾插法):

  • Step 1. 要先处理插入结点1的指向,分别把结点1的前驱后继指向
  • Step 2. 再来解决原先结点的指向,如图所示把head->next和end->prev指向1,即插入完成。

(注: 这里1,2步不能搞混,要先执行第一步在执行第二步,反过来则会出错,可以尝试一下并打log体会)

删除操作:

  • Step 1. 同理,要先处理删除结点1的前后结点指向,如图所示,分别把head->next指向end,end->prev指向head即可;
  • Step 2. 最后在把结点1删除,即删除完成。

(注: 这里1,2步不能搞混,要先执行第一步在执行第二步,反过来则会出错,可以尝试一下并打log体会)


三、代码实现

。每个代码块都写了注释,方便理解,代码还可以改进;
代码如下(示例):
解法一:

class MyLinkedList {//创建头结点,尾结点private Node head, end;//链表长度private int length;public MyLinkedList() {// 链表初始化this.head = new Node(-1, null, null);this.end = new Node(-1, null, null);// 连接链表初始节点this.head.setNode(null, this.end);this.end.setNode(this.head, null);this.length = 0;}//获取当前元素public int get(int index) {//安全处理if(index >= 0 && index+1 <= this.length){//当前结点// 使用贪心每次都从最近的地方开始找Node temp = index <= this.length/2 ? this.head : this.end;// 可优化代码将其抽离成模块if(index <= this.length/2){// 从头结点for(int i = 0; i <= index; i++){temp = temp.next;}}else{for(int i = 0; i <= this.length - index - 1; i++){temp = temp.prev;}}return temp.val;}return -1;}//头插法public void addAtHead(int val) {Node temp = new Node(val,null,null);// 第一步先处理插入的元素指向temp.next = this.head.next;temp.prev = this.head;// 第二步在处理原先的元素指向this.head.next.prev = temp;this.head.next = temp;this.length++;// Nodeshow();}//尾插法public void addAtTail(int val) { Node temp = new Node(val,null,null);// 双向链表// 第一步先处理插入的元素指向temp.next = this.end;temp.prev = this.end.prev;// 第二步在处理原先的元素指向this.end.prev.next = temp;this.end.prev = temp;this.length++;// Nodeshow();}// 在第index个节点之前添加值为val的节点public void addAtIndex(int index, int val) {//安全处理if(index >= 0 && index <= this.length){//当前结点Node temp = index <= this.length/2 ? this.head : this.end;Node temp_node = new Node(val, null,null);// 使用贪心每次都从最近的地方开始找// 可优化代码将其抽离成模块if(index <= this.length/2){// 从头结点开始寻找要插入的位置for(int i = 0; i < index; i++){temp = temp.next;}//插入结点 temp结点为要插入位置的前一个结点temp_node.next = temp.next;temp_node.prev = temp;temp.next.prev = temp_node;temp.next = temp_node;}else{// 从尾节点开始找到要插入的位置for(int i = 0; i <= this.length - index - 1; i++){temp = temp.prev;}// 插入结点 temp结点为要插入位置的当前结点temp_node.next = temp;temp_node.prev = temp.prev;temp.prev.next = temp_node;temp.prev = temp_node;                }this.length++;// Nodeshow();}}public void deleteAtIndex(int index) {//安全处理// System.out.println("this.length = " + this.length);if(index >= 0 && index+1 <= this.length){Node temp = this.head;//双向链表 找到删除结点for(int i = 0; i <= index; i++){temp = temp.next;}temp.next.prev = temp.prev;temp.prev.next = temp.next;this.length--;// Nodeshow();}}public void Nodeshow(){Node temp = head;while(temp.next != null){System.out.print(temp.val + " ");temp = temp.next;}System.out.print(temp.val + " ");System.out.println();}
}//先创建结点对象,双向链表
public class Node{public int val;public Node prev; //前驱结点public Node next; //后续结点public Node(int val){this.val = val;this.prev = null;this.next = null;}public Node(int val, Node prev,Node next){this.val = val;this.prev = prev;this.next = next;}public void setNode(Node prev, Node next){this.prev = prev;this.next = next;}
}

提交结果:

三、单向链表代码实现

class MyLinkedList {//创建头结点,尾结点private Node head;//链表长度private int length;public MyLinkedList() {//链表初始化this.head = new Node(-1, null);this.end = new Node(-1, null);this.length = 0;}//获取当前元素public int get(int index) {//安全处理if(index >= 0 && index+1 <= this.length){//当前结点Node temp = this.head;for(int i = 0; i <= index; i++){temp = temp.next;}return temp.val;}return -1;}//头插法public void addAtHead(int val) {Node temp = new Node(val,null);temp.next = this.head.next;this.head.next = temp;this.length++;// Nodeshow();}//尾插法public void addAtTail(int val) { Node temp = new Node(val,null);Node temp_head = this.head;//找到尾部while(temp_head.next != null) temp_head = temp_head.next;temp_head.next = temp;this.length++;// Nodeshow();}public void addAtIndex(int index, int val) {//安全处理if(index >= 0 && index <= this.length){//当前结点Node temp = this.head;Node temp_node = new Node(val, null);for(int i = 0; i < index; i++){temp = temp.next;}//插入结点temp_node.next = temp.next;temp.next = temp_node;this.length++;// Nodeshow();}}public void deleteAtIndex(int index) {//安全处理// System.out.println("this.length = " + this.length);if(index >= 0 && index+1 <= this.length){Node temp = this.head;//找到删除结点的前一个结点for(int i = 0; i <= index-1; i++){temp = temp.next;}// System.out.print(temp.val + " === ");temp.next = temp.next.next;this.length--;// Nodeshow();}}public void Nodeshow(){Node temp = head;while(temp.next != null){System.out.print(temp.val + " ");temp = temp.next;}System.out.print(temp.val + " ");System.out.println();}
}//先创建结点对象
public class Node{public int val;public Node next;public Node(int val){this.val = val;}public Node(int val, Node next){this.val = val;this.next = next;}
}

总结

以上就是今天要讲的内容,本题单纯就是对数据结构链表构成的考察,由于题中涉及到一些对中间变量的操作,所以采用双向链表来进行解决,加上贪心算法来进行查询位置加快运行速度。不过这里关键点还是在于要定义好链表的边界,这一点要理清楚。不然在编写过程容易缺失部分数据处理(本人踩的坑)。所以就赶紧记录一下这时刻。

LeetCode刷题---707. 设计链表(双向链表-带头尾双结点)相关推荐

  1. 面试算法LeetCode刷题班—BAT面试官带你刷真题、过笔试

    课程名称: <面试算法LeetCode刷题班> --BAT面试官带你刷真题.过笔试 主讲老师: 林老师 BAT资深研发工程师(T7/P8级),致力于搜索引擎及其子系统的研发.迭代与优化,数 ...

  2. 【leetcode刷题日记】链表

    各个数据结构和算法的链接总结如下: 待补充. 链表 总结:本部分内容其实就是考察对指针的操作.通过指针会改变对象指向的方向,这些都是需要注意.有一些技巧,类似于快慢指针,加一个脑袋(哨兵/头节点),h ...

  3. leetcode刷题:删除链表中的节点

    题目: 分析: 删除链表中的节点的常见的方法是定位到待删除节点的上一个节点,修改上一个节点的 \textit{next}next 指针,使其指向待删除节点的下一个节点,即可完成删除操作. 这道题中,传 ...

  4. leetcode刷题:相交链表

    题目: 分析: 判断两个链表是否相交,可以使用哈希集合存储链表节点. 首先遍历链表 \textit{headA}headA,并将链表 \textit{headA}headA 中的每个节点加入哈希集合中 ...

  5. leetcode刷题:反转链表I

    1.题目 分析: 代码如下: //迭代反转法,head 为无头节点链表的头指针 link * iteration_reverse(link* head) {if (head == NULL || he ...

  6. 【数据结构】(图解)leetcode刷题之单链表(中)

  7. C#LeetCode刷题-链表

    链表篇 # 题名 刷题 通过率 难度 2 两数相加   29.0% 中等 19 删除链表的倒数第N个节点   29.4% 中等 21 合并两个有序链表 C#LeetCode刷题之#21-合并两个有序链 ...

  8. C#LeetCode刷题-设计

    设计篇 # 题名 刷题 通过率 难度 146 LRU缓存机制 33.1% 困难 155 最小栈 C#LeetCode刷题之#155-最小栈(Min Stack) 44.9% 简单 173 二叉搜索树迭 ...

  9. 个人LeetCode刷题记录(带题目链接及解答)持续更新

    Leetcode 刷题 注:~[完成]代表还有一些方法没看,最后再看 一.一些需要重刷的典型题: 1.快速排序,归并排序,堆排序(递归的思想) 2.链表中的回文链表,其中的快慢指针,多看,多练 3.链 ...

最新文章

  1. 深到骨子里的自律,是每周坚持刷几篇最新论文 | PaperDaily #10
  2. java费波拉切_面试题 - 不再犯错 - 博客园
  3. 画时序图 visual_时序图的初步了解
  4. IDEA自动生成 构造方法 get set方法
  5. Problem A: 童年生活二三事
  6. 靶形数独(洛谷-P1074)
  7. 郑州轻工业学院OJ-杨辉三角
  8. ngui中 代码调用按钮事件(后来改成了按钮绑定键盘..)
  9. Java多线程——线程范围内共享变量和ThreadLocal
  10. 啊哈算法—解救小哈(深度优先搜索)
  11. 数据库SQL优化大总结1之- 百万级数据库优化方案
  12. 菜鸡的求学之路-JavaScript
  13. java mail 匿名_java开发邮件发送匿名
  14. 最大团问题(迭代回溯法)
  15. td超过的文字设置省略号
  16. Part 2 如何进行埋点(内附埋点文档模板)
  17. docker部署html页面,Docker 案例: 在容器中部署静态网站
  18. 高鸿业西方经济学微观部分第7版笔记
  19. modelsim使用protect加密verilog代码
  20. 如何调出IPGUARD控制台维护里的命令行

热门文章

  1. iphonex正面图_【苹果iPhoneX评测】刘海上八个模块各显神通_苹果 iPhone X _手机评测-中关村在线...
  2. 电商微信小程序(教你一个页面一个数据接口搞定所有分类订单页面(未支付 未发货 已发货 全部订单))
  3. Au 音频效果参考:延迟与回声
  4. 如何将电脑屏幕投放到电视上?电视投屏软件可以帮忙!
  5. 邮件发件人、标题、收件人等位置显示中文
  6. 微信模板消息跳转小程序指定页面(非首页)的问题
  7. 需要控制好情绪,调整好心态
  8. Linux OTG当串口、网口、U盘
  9. 思博伦成功支持业界最高密度768*100G数据中心交换机测试
  10. node医保药品集中采购平台-采购系统的设计与实现 毕业设计-附源码271542