php反转部分单向链表

* inversePart

 给定一个单向链表的头结点head, 以及2个整数from和to,在单向链表上把第from个节点到to个节点这一部分进行反转

e.g.

1->2->3->4->5->null, from=2, to=4

调整结果为: 1->4->3->2->5->null

1->2->3->null, from=1, to=3

调整结果为: 3->2->1->null

要求:

1. 如果链表长度为N, 时间复杂度要求为O(N), 额外空间复杂度要求为O(1)

2. 如果不满足1<=from<=to<=N, 则不用调整

解答:

1. 先判断是否满足1<=from<=to<=N, 如果不满足, 则直接返回原来的头节点

2. 找到第from-1个节点fPre和第to+1个节点tPos。fPre即是要反转部分的前一个节点,tPos是反转部分的后一个节点。

   把反转部分先反转,然后正确地连接fPre和tPos

3. 如果fPre为null,说明反转部分是包含头结点的,则返回新的头结点,也就是没反转之前反转部分的最后一个节点,

  也是反转之后反转部分的第一个节点; 如果fPre不为null,则返回旧的头结点.

<?php
/**
 * Created by PhpStorm.
 * User: Mch
 * Date: 8/11/18
 * Time: 00:25
 */
class Node {
    public $value;
    public $next;
    public function __construct($data) {
        $this->value = $data;
        $this->next = null;
    }
}

class LinkedList implements Iterator, Countable {
    private $head;
    private $cur;

    public function __construct() {
        $this->head = $this->cur = null;
    }

    public function isEmpty() {
        return is_null($this->head);
    }

    public function count() {
        $p = $this->head;
        $count = 0;
        while ($p !== null) {
            $p = $p->next;
            $count++;
        }
        return $count;
    }
    public function current() {
        if ($this->isEmpty()) {
            return null;
        }
        return $this->cur->value;
    }
    public function next() {
        if (is_null($this->cur)) {
            return null;
        }
        $this->cur = $this->cur->next;
    }
    public function rewind() {
        $this->cur = $this->head;
    }

    public function valid() {
        return !is_null($this->cur);
    }
    public function key() {
        $p = $this->head;
        $key = 0;
        while ($p !== $this->cur) {
            $p = $p->next;
            $key++;
        }
        return $key;
    }
    public function push($value) {
        if ($this->isEmpty()) {
            $this->head = new Node($value);
            $this->cur = $this->head;
        } else {
            $this->cur = $this->head;
            while ($this->cur->next !== null) {
                $this->cur = $this->cur->next;
            }
            $this->cur->next = new Node($value);
        }
        return $this;
    }

    public function forEach(callable $callback, mixed $userdata = null) {
        $this->rewind();
        while($this->valid()) {
            call_user_func($callback, $this->current(), $this->key(), $userdata);
            $this->next();
        }
    }

    public function reverse() {
        if ($this->isEmpty())
            return;
        if ($this->count() < 2)
            return;
        $prev = null;
        $cur = $this->head;
        while ($cur) {
            // save next
            $next = $cur->next;
            // move cur to head
            $this->head = $cur;
            $cur->next = $prev;
            // iterate
            $prev = $cur;
            $cur = $next;
        }
    }

    /**
     * 给定一个单项链表的头结点head, 以及两个整数from和to,
     * 在单向链表上把第from个节点到第to个节点的这一部分反转
     * 例如:
     *  1->2->3->4->5->null, from=2, to=4
     * 调整结果为: 1->4->3->2->5->null
     */
    public function reversePart(int $from, int $to) {
        $len = 0;
        $node1 = $this->head;  // iterator
        $fPre = null;  // 反转部分的前一个节点
        $tPos = null;  // 反转部分的后一个节点
        // 找到$fPre, $tPos位置
        while ($node1 != null) {
            $len++;
            if ($len === $from-1) {
                $fPre = $node1;
            }
            if ($len === $to+1) {
                $tPos = $node1;
            }
            $node1 = $node1->next;
        }
        // 不满足 1 <= $from <= $to <= $len 场合直接返回
        if ($from > $to || $from < 1 || $to > $len) {
            return $this->head;
        }
        $node1 = $fPre === null ? $this->head : $fPre->next;
        $node2 = $node1->next;
        $node1->next = $tPos;
        $next = null;
        while ($node2 != $tPos) {
            $next = $node2->next;
            $node2->next = $node1;
            $node1 = $node2;
            $node2 = $next;
        }
        if ($fPre != null) {
            $fPre->next = $node1;
            return $this->head;
        }
        // 换头
        $this->head = $node1;
    }

}

test:

$list = new LinkedList();

for ($i = 65; $i < 91; $i++) {
    $list->push(chr($i));
}

$list->forEach(function($value, $index) {
    printf("[%d] => %s<br />", $index, $value);
});
echo '-------------------<br />';
// $list->reverse();
$list->reversePart(2, 4);
$list->forEach(function($value, $index) {
    printf("[%d] => %s<br />", $index, $value);
});

[0] => A
[1] => B
[2] => C
[3] => D
[4] => E
...
-------------------
[0] => A
[1] => D
[2] => C
[3] => B
[4] => E
...

猜你喜欢

转载自blog.csdn.net/fareast_mzh/article/details/81638678