算法训练day2 | php | 203.移除链表元素 ,707.设计链表 ,206.反转链表

一、力扣题203. 移除链表元素

给你一个链表的头节点 head 和一个整数 val ,请你删除链表中所有满足 Node.val == val 的节点,并返回 新的头节点 。

示例 1:

输入:head = [1,2,6,3,4,5,6], val = 6
输出:[1,2,3,4,5]

示例 2:

输入:head = [], val = 1
输出:[]

示例 3:

输入:head = [7,7,7,7], val = 7
输出:[]

        在做本题前复习了链表的基础知识,发现这道题难度不高,只要对链表的结构认知清晰就能做出来,在此之前没做过链表相关的算法,在语法上对于链表和节点的定义费了点时间。

方法1

        删除链表元素分为两种情况,第一种是删除头结点,也就是第一个元素,把头结点的下一个节点定义为新的头结点就可以了;第二种是删除头结点以外的元素,需要将目标结点的上一个节点的next改为指向目标节点的下一个节点,如下图所示:

         需要注意的是,当头结点为目标值时,设置下一个结点为新的头结点后,这个新的头结点也可能是目标值,所以需要先遍历,将头结点为目标值的情况全部去除完后,再来遍历删除头结点以外的目标元素。

function removeElements($head, $val) {
        while($head != null && $head->val == $val) {
            $head = $head->next;
        }
        $cur = $head;
        while($cur->next != null) {
            if($cur->next->val == $val) {
                $cur->next = $cur->next->next;
            } else {
                $cur = $cur->next;
            }
        }
        return $head;
    }

方法2:虚拟头结点

        为了更加方便,可以设置一个虚拟头结点,也就是在原来的头结点前新增一个结点,这样删除链表元素时,就只有一种情况:删除头结点以外的元素。

        另外需要注意一点,删除完成后的链表,它的真头结点不一定是原来的头结点,也可能头结点是目标值被删除了,所以不能返回题目原来给我们的$head头结点,而应该返回$dummpHead->next这个头结点。

function removeElements($head, $val) {
        $dummyHead = new ListNode();
        $dummyHead->next = $head; 
        $cur = $dummyHead;
        while($cur->next != null) {
            if($cur->next->val == $val) {
                $cur->next = $cur->next->next;
            } else {
                $cur = $cur->next;
            }
        }
        return $dummyHead->next;
    }

二、力扣题707. 设计链表 

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

在链表类中实现这些功能:

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

示例:

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

        这道题我没有事先去看讲解,自己做出来辽!(叉腰一下)

        这道题难度不高,主要考察链表的增删查操作,但是有点繁琐,我写的时候在删除元素的方法里就忘记把链表个数减一了,num和dummpHead作为全局变量本身是要着重注意的。

class MyLinkedList {
    /**
     */

    private $dummyHead;
    private $num;
    function __construct() {
        $this->num = 0;
        $this->dummyHead = new ListNode();
    }

    /**
     * @param Integer $index
     * @return Integer
     */
    function get($index) {
        if($index < 0 || $index >= $this->num) {
            return -1;
        }
        $cur = $this->dummyHead;
        for($i = 0; $i <= $index; $i++) {
            $cur = $cur->next;
        }
        return $cur->val;
    }

    /**
     * @param Integer $val
     * @return NULL
     */
    function addAtHead($val) {
        $new = new ListNode($val);
        $new->next = $this->dummyHead->next;
        $this->dummyHead->next = $new;
        $this->num++;
    }

    /**
     * @param Integer $val
     * @return NULL
     */
    function addAtTail($val) {
        $new = new ListNode($val);
        $last = $this->dummyHead;
        while($last->next != null) {
            $last = $last->next;
        }
        $last->next = $new;
        $new->next = null;
        $this->num++;
    }

    /**
     * @param Integer $index
     * @param Integer $val
     * @return NULL
     */
    function addAtIndex($index, $val) {
        if($index <= 0) {
            $this->addAtHead($val);
            return;
        }
        if($index == $this->num) {
            $this->addAtTail($val);
            return;
        }
        if($index > $this->num) {
            return;
        }

        $new = new ListNode($val);
        $i = 0;
        $prev = $this->dummyHead;
        while($i != $index) {
            $prev = $prev->next;
            $i++;
        }
        $new->next = $prev->next;
        $prev->next = $new;
        $this->num++;
        
    }

    /**
     * @param Integer $index
     * @return NULL
     */
    function deleteAtIndex($index) {
        if($index >= 0 && $index < $this->num) {
            $i = 0;
            $prev = $this->dummyHead;
            while($i != $index) {
                $prev = $prev->next;
                $i++;
            }
            $prev->next = $prev->next->next;
            $this->num--;
        }
    }
}

/**
 * Your MyLinkedList object will be instantiated and called as such:
 * $obj = MyLinkedList();
 * $ret_1 = $obj->get($index);
 * $obj->addAtHead($val);
 * $obj->addAtTail($val);
 * $obj->addAtIndex($index, $val);
 * $obj->deleteAtIndex($index);
 */

三、力扣题206. 反转链表

给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。

示例 1:

输入:head = [1,2,3,4,5]
输出:[5,4,3,2,1]

示例 2:

输入:head = [1,2]
输出:[2,1]

示例 3:

输入:head = []
输出:[]

        这道题是直接去看的视频讲解,我在看题的时候想的是遍历到最后再一个个反过来,感觉到自己思维的局限性,没有认识和运用到链表本身的特性。

        本题的解法有些类似双指针,也是设置两个结点。因为要将链表反转过来,所以只要把链表中的箭头指向都反转一下就好了,然后最后一个结点就变成反转链表的头结点,而原来的头结点的next就变成指向null。

        我们从链表的头结点开始反转,所以需要设置两个结点a和b,a放在头结点上,b设为null,然后把 a 指向 b ,这样头结点就指向null了,然后把 b 移到 a 的位置, 而 a 移到头结点原先指向的下一个结点,再次反转使 a -> b 

         而在a、b 向右移动的过程中,需要有一个中间值才能完成赋值, 就像两个变量互换值也需要中间值。

        移动到最后,a 会指向null,b会指向最后一个结点,此时的反转就已经完成了,所以判断反转完成的条件就是 a 为 null。

方法1:

function reverseList($head) {
        $cur = $head;
        $prev = null;
        while($cur != null) {
            $temp = $cur->next;
            $cur->next = $prev;
            $prev = $cur;
            $cur = $temp;
        }
        return $prev;
    }

方法2:递归 

        递归的逻辑和上面的方法类似,只是使用递归会更加简洁。

function reverseList($head) {
        $cur = $head;
        $prev = null;
        while($cur != null) {
            $temp = $cur->next;
            $cur->next = $prev;
            $prev = $cur;
            $cur = $temp;
        }
        return $prev;

        return $this->reverse($head, null);
    }

    function reverse($cur, $prev) {
        if($cur == null) {
            return $prev;
        }
        $temp = $cur->next;
        $cur->next = $prev;
        reverse($temp, $cur);
    }

        

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值