算法训练-Day3|203.移除链表元素 707.设计链表 206.反转链表

链表理论基础 

 ①链表是一种通过指针串联在一起的线性结构,由数据域和指针域两部分构成。

②跟数组不一样,数组在内存中是连续存放的,链表在内存中不是连续分布的。

③链表有单链表、双链表和循环链表。

203.移除链表元素

把一些变量的定义名意义记住,根据意义去命名变量。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode() {}
 *     ListNode(int val) { this.val = val; }
 *     ListNode(int val, ListNode next) { this.val = val; this.next = next; }
 * }
 */
class Solution {
    public ListNode removeElements(ListNode head, int val) {
           if(head == null)
                return head;   //考虑空节点情况
           ListNode dummy = new ListNode(-1);   //创建数值为-1的头结点
           dummy.next = head;       //指向第一个节点
           ListNode pre = dummy;   //当前节点的前驱节点
           ListNode cur = head;  //当前节点

           while(cur != null){   //遍历所有节点

               if(cur.val == val)
                    pre.next = cur.next;
                else
                    pre = cur;
                
                cur = cur.next;
                    
           }
           return dummy.next;   //返回头节点

    }
}

707.设计链表

单链表

在插入或者删除操作时,一般都要找到待插入或者待删除节点的前驱节点,然后再进行插入或者删除操作。

设置虚拟头节点的目的是为了在删除或者插入操作时,第一个节点和其他节点可以统一操作,而不需要分类讨论。

这道题目设计链表的五个接口:

  • 获取链表第index个节点的数值
  • 在链表的最前面插入一个节点
  • 在链表的最后面插入一个节点
  • 在链表第index个节点前面插入一个节点
  • 删除链表的第index个节点
public class ListNode{
    int val;
    ListNode  next;
    ListNode(){}
    ListNode(int val){
        this.val = val;
    }
}


class MyLinkedList {
    int size;  //存储链表中元素个数
    ListNode head;   //这里的head就是虚拟头节点

    public MyLinkedList() {
        size = 0;
        head = new ListNode(0);
    }
    
    public int get(int index) {

        if(index < 0 || index >= size)
            return -1;
        
        ListNode cur = head;

        //因为有虚拟头节点,所以实际上要找第(index+1)个节点
        for(int i = 0;i <= index ; i++)
            cur = cur.next;
        
        return cur.val;
    }
    
    //其实就是在下标为0的节点前插入一个新节点
    public void addAtHead(int val) {
        addAtIndex(0,val);
    }
    
    public void addAtTail(int val) {
        addAtIndex(size,val);
    }
    
    //找下标为index节点的的前一节点进行插入操作
    public void addAtIndex(int index, int val) {
        if(index < 0 ||index > size)
            return ;

        ListNode pre = head;
        for(int i = 0; i < index;i++)
            pre = pre.next;
        
        ListNode addNode = new ListNode(val);  //创建值为val的节点
        addNode.next = pre.next;
        pre.next = addNode;
        size++;
    }
    
    public void deleteAtIndex(int index) {

        if(index < 0 || index >= size)
            return;

        ListNode pre = head;

        //找到待删除节点的前一节点(设置了虚拟头节点,所以可以统一操作)
        for(int i = 0;i < index;i++)
            pre = pre.next;
        
        pre.next = pre.next.next;
        size--;
    }
}

双链表(后面有时间补一下双链表是如何进行这些基础操作的)

206.反转链表 

        如果再定义一个新的链表,实现链表元素的反转,这是对内存空间的浪费,因此不用定义一个新链表。其实只需要改变链表的next指针的指向,直接将链表反转 ,而不用重新定义一个新的链表。  

        首先定义一个cur指针,指向头结点,再定义一个pre指针,初始化为null。

        然后就要开始反转了,首先要把 cur->next 节点用tmp指针保存一下,也就是保存一下这个节点。

        为什么要保存一下这个节点呢,因为接下来要改变 cur->next 的指向了,将cur->next 指向pre ,此时已经反转了第一个节点了。

        接下来,就是循环走如下代码逻辑了,继续移动pre和cur指针。

        最后,cur 指针已经指向了null,循环结束,链表也反转完毕了。 此时我们return pre指针就可以了,pre指针就指向了新的头结点。

①双指针法

class Solution {
    public ListNode reverseList(ListNode head) {
       
       ListNode pre = null; //初始化为null
       ListNode cur = head;   //
       ListNode temp;  //因为接下来要改变 cur->next 的指向了,将cur->next 指向pre,此时已经反转了第一个节点了.

       while(cur != null){
           temp = cur.next;  //因为cur节点的指针要改变方向了,因此要存放下一节点
           cur.next = pre;
           pre = cur;
           cur = temp;
       }
       return  pre;
    }
}

②递归法

递归法跟双指针法原理一样,参考下模版就行。

  • 14
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值