* 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
...