训练营Day3

文章介绍了链表的基础定义,包括节点结构和常见操作如删除、添加节点。在LeetCode题目中,讨论了删除链表元素的问题,强调了操作前需找到目标节点的前驱。同时,提供了设计链表的实现,包括单链表和双向链表的添加、删除、获取元素等方法。
摘要由CSDN通过智能技术生成

链表

链表的定义(代码)

 public class ListNode {
     // 结点的值
     int val;
 ​
     // 下一个结点
     ListNode next;
 ​
     // 节点的构造函数(无参)
     public ListNode() {
     }
 ​
     // 节点的构造函数(有一个参数)
     public ListNode(int val) {
         this.val = val;
     }
 ​
     // 节点的构造函数(有两个参数)
     public ListNode(int val, ListNode next) {
         this.val = val;
         this.next = next;
     }
 }

链表操作


删除节点

添加节点

除了查找,其他的增删改操作,都应该先找到目标位置的前驱元素,这样才能进行操作。这种执行流程也是基于链表的设计特点考虑的(next/pre节点)。

LeetCode.203 移除链表元素

遇到的问题:

结果不能返回head,因为后续的删除操作并没有影响到Head的指向

 class Solution {
     public ListNode removeElements(ListNode head, int val) {
         if (head == null){
             return head;
         }
         ListNode dummy = new ListNode(-1 , head);
         ListNode pre = dummy;
         ListNode node = dummy.next;
         while(pre.next != null){
             if(node.val == val){
                 ListNode temp = node.next;
                 pre.next = node.next;
                 node = temp;
             }
             else{
                 pre = pre.next;
                 node = node.next;
             }
             
         }
         
         return dummy.next;//此处不能返回head,因为后续的删除操作并没有影响到Head的指向
     }
 }

LeetCode.707 设计链表

遇到的问题:

实现的逻辑还是很好理解的,但是要多动手去画链表的各种操作过程,脑测很容易搞不清楚应该使用前驱还是当前节点。

单链表实现:
 //单链表
 class ListNode{
     
     int val;
     
     ListNode next;
 ​
     public ListNode(){}
 ​
     public ListNode(int val){
         this.val = val;
     }
 ​
 }
 class MyLinkedList {
 ​
     ListNode head;
     int size;
 ​
     public MyLinkedList() {
         size = 0;
         head = new ListNode(0);
     }
     
     public int get(int index) {
         if(index >= size || index < 0){
             return -1;
         }
         ListNode cur = head; 
         for(int i = 0 ; i <= index ; i++){
             cur = cur.next;
         }
         return cur.val;
     }
     
     public void addAtHead(int val) {
         ListNode newNode = new ListNode(val);
         ListNode temp = head.next;
         head.next = newNode;
         newNode.next = temp;
         size++;
     }
     
     public void addAtTail(int val) {
         ListNode pre;
         pre = head;//一开始是head.next想着直接找到末尾对应的节点
         for(int i = 0 ; i < size ; i++){
             pre = pre.next;
         }
         ListNode newNode = new ListNode(val);
         pre.next = new ListNode();
         pre.next = newNode;
         size++;
     }
     
     public void addAtIndex(int index, int val) {
         if(index > size || index < 0){
             return;
         }
         size++;
         ListNode pre = head;
         for(int i = 0 ; i < index ; i++){
             pre = pre.next;
         }
         ListNode newNode = new ListNode(val);
         newNode.next = pre.next;
         pre.next = newNode;
         
         
     }
     
     public void deleteAtIndex(int index) {
         if(index >= size || index <0){
             return;
         }
         size--;
         if(index == 0){
             head = head.next;
             return;
         }
 ​
         ListNode cur = head;
             for(int i = 0 ; i < index ; i++){
                cur = cur.next;
             }
         cur.next = cur.next.next;
         
     
         
     }
 }
双向链表实现:
 //双向链表
 class ListNode{
     
     int val;
     
     ListNode next;
     ListNode pred;
 ​
     public ListNode(){}
 ​
     public ListNode(int val){
         this.val = val;
     }
 ​
 }
 class MyLinkedList {
 ​
     ListNode head;
     int size;
 ​
     public MyLinkedList() {
         size = 0;
         head = new ListNode(0);
     }
     
     public int get(int index) {
         if(index >= size || index < 0){
             return -1;
         }
         ListNode cur = head; 
         for(int i = 0 ; i <= index ; i++){
             cur = cur.next;
         }
         return cur.val;
     }
     
     public void addAtHead(int val) {
         size++;
         ListNode newNode = new ListNode(val);
         ListNode pre = head;
         ListNode temp = pre.next;
         if(pre.next != null){
             pre.next.pred = newNode;
         }
         newNode.pred = pre;
         pre.next = newNode;
         newNode.next = temp;
         
         
 ​
     }
     
     public void addAtTail(int val) {
         ListNode pre;
         pre = head;//一开始是head.next想着直接找到末尾对应的节点
         for(int i = 0 ; i < size ; i++){
             pre = pre.next;
         }
         ListNode newNode = new ListNode(val);
         pre.next = new ListNode();
         pre.next = newNode;
         newNode.pred = pre;
         size++;
     }
     
     public void addAtIndex(int index, int val) {
         if(index > size || index < 0){
             return;
         }
         size++;
         ListNode pre = head;
         for(int i = 0 ; i < index ; i++){
             pre = pre.next;
         }
         ListNode newNode = new ListNode(val);
         newNode.pred = pre;
         if(pre.next != null){
             pre.next.pred = newNode;
         }
         newNode.next = pre.next;
         pre.next = newNode;
         
         
     }
     
     public void deleteAtIndex(int index) {
         if(index >= size || index <0){
             return;
         }
         size--;
         if(index == 0){
             head = head.next;
             return;
         }
 ​
         ListNode cur = head;
             for(int i = 0 ; i < index ; i++){
                cur = cur.next;
             }
         if(cur.next.next != null){
             cur.next.next.pred = cur;
         }
         
         cur.next = cur.next.next;
         
     
         
     }
 }
 ​
 ​

LeetCode.206 翻转链表

看了视频好理解多了,但是可能还是不够熟练,后续要多多回看

易混淆:

要注意循环的终止条件,是基于翻转链表的基本操作的,每进行一次翻转,前驱和当前节点都会向后移动一位

也别忘了在此之前要保存cur.next节点以供cur的在翻转之后向后移动

 class Solution {
     public ListNode reverseList(ListNode head) {
         ListNode pre = null;
         ListNode cur = head;
         ListNode temp = null;
         while(cur != null){
             temp = cur.next;
             cur.next = pre;
             pre = cur;
             cur = temp;
         }
     return pre;
     }
 }
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值