以给定大小的组反转链表
Reverse a Linked List in groups of given size
给定一个链表,一次反转链表k的节点和return其修改后的列表。
k为正整数,小于等于链表长度。如果节点数不是k的倍数,那么最后遗漏的节点应该保持原样。
您不能更改列表节点中的值,只能更改节点本身。
但是当我使用下面的代码时,我的输出:[3,2,1,5,4]
如何以正确的方式做到这一点?
class Solution
{
public static Node reverse(Node head, int k)
{
Node prev = null;
Node dummy = head;
int c = 0;
while(dummy != null && c < k ) {
Node next = dummy.next;
dummy.next = prev;
prev = dummy;
dummy = next;
c++;
}
if(dummy != null) {
head.next = reverse(dummy,k);
}
return prev;
}
}
首先,编写一个计算列表长度的方法。稍后,通过每次增加 c
.
时增加一些计数器来跟踪您当前正在反转的项目的索引
稍后,与其在重复调用 reverse
方法之前检查 if (dummy != null
),不如检查列表中是否还有足够的元素 - 通过比较在以计数器开头。
我写一个辅助方法
private boolean areAtLeastNNodes(int n, Node head)
因此,在尝试反转任何东西之前,我会调用此方法。如果returns为假,我将弃权。
我自己的 areAtLeastNNodes()
版本是递归的,因为我觉得它更简单。它也可以是迭代的。
我的建议是对每个子列表传递两次,一次用于计数,一次用于反转。这感觉很浪费。这当然可以避免,但它会很复杂,我不想打扰。
使用递归不需要计算列表的长度。但是,指针操作有点棘手。
public static Node reverseK(Node head, int k)
{
return reverseK(head, head, k, k);
}
private static Node reverseK(Node head, Node node, int i, int k)
{
// we reached a final sequence of length < k, return the current head
if(node == null)
return head;
if(i == 1)
{
// we reached the end of a sequence of length k.
// Reverse the next sequence, return the new head.
head.next = reverseK(node.next, node.next, k, k);
return node;
}
// Store current next as it will be modified by the recursive call.
Node next = node.next;
Node newHead = reverseK(head, node.next, i-1, k);
// If the current sequence was of length k, reverse pointers.
if(newHead != head)
{
next.next = node;
}
return newHead;
}
测试:
int[] a = {1, 2, 3, 4, 5};
Node head = build(a);
print(head);
head = reverseK(head, 3);
print(head);
输出:
1 2 3 4 5
3 2 1 4 5
我会考虑使用模数 k 的方法。在迭代的每一步,当前节点都可以从函数调用者或递归调用的结果中获取其“下一个”字段的值。
Python代码:
def print_list(node, k):
i = 0
s = ""
while node:
s += node['val']
node = get_next(node)
if i == k - 1:
s += " "
i = (i + 1) % k
print(s)
def get_next(node):
return node['next']
def set_next(node, new_next):
node['next'] = new_next
# Returns (this_block_head, next_block_head)
def reverse(node, k, new_next=None, m=0):
if k == 1:
return (node, None)
# We use 'this_block_head' as a signal
# that when returns this current node,
# it means the block's length is less than
# k, and therefore will not be reversed.
if not node:
return (None, None) if m == 0 else (new_next, None)
# The first node in
# a block doesn't get
# a next parameter and
# must get it from the
# recursive call.
next_param = None if m == k - 1 else node
(this_block_head, next_block_head) = reverse(get_next(node), k, next_param, (m + 1) % k)
if this_block_head == node:
# When 'new_next' is null,
# this is a beginning of a block
# so the caller needs the node
# as its 'this_block_head'.
return (new_next if new_next else node, None)
# The last in the block,
# which will become first,
# here 'this_block_head' is
# actually 'next_block_head'
if m == k - 1:
set_next(node, new_next)
return (node, this_block_head)
set_next(node, next_block_head if m == 0 else new_next)
return (this_block_head, next_block_head)
输出:
def reset_list():
global a, b, c, d, e, f
f = {'val': 'f', 'next': None}
e = {'val': 'e', 'next': f}
d = {'val': 'd', 'next': e}
c = {'val': 'c', 'next': d}
b = {'val': 'b', 'next': c}
a = {'val': 'a', 'next': b}
reset_list()
print_list(a, 6) # abcdef
reverse(a, 2)
print_list(b, 2) # ba dc fe
print("")
reset_list()
print_list(a, 6) # abcdef
reverse(a, 3)
print_list(c, 3) # cba fed
print("")
reset_list()
print_list(a, 6) # abcdef
reverse(a, 4)
print_list(d, 4) # dcba ef
你可以这样做,
对于以下示例,您将收到此回复
4 -> 3 -> 2 -> 1 -> 5 -> 6
public class Main {
public static void main(String[] args) {
Node n1 = new Node(1);
Node n2 = new Node(2);
Node n3 = new Node(3);
Node n4 = new Node(4);
Node n5 = new Node(5);
Node n6 = new Node(6);
n1.next = n2;
n2.next = n3;
n3.next = n4;
n4.next = n5;
n5.next = n6;
System.out.println(reverse(n1, n1, n1.next, 4));
}
public static Node reverse(Node fst, Node lst, Node nxt, int k) {
if (k == 1) {
return fst;
} else {
Node m1 = fst;
Node m2 = nxt.next;
fst = nxt;
fst.next = m1;
lst.next = m2;
return reverse(fst, lst, lst.next, --k);
}
}
}
class Node {
public int val;
public Node next;
public Node(int val) {
this.val = val;
}
@Override
public String toString() {
if (next == null) {
return "" + val;
} return val + " -> " + next.toString();
}
}
给定一个链表,一次反转链表k的节点和return其修改后的列表。
k为正整数,小于等于链表长度。如果节点数不是k的倍数,那么最后遗漏的节点应该保持原样。
您不能更改列表节点中的值,只能更改节点本身。
但是当我使用下面的代码时,我的输出:[3,2,1,5,4]
如何以正确的方式做到这一点?
class Solution
{
public static Node reverse(Node head, int k)
{
Node prev = null;
Node dummy = head;
int c = 0;
while(dummy != null && c < k ) {
Node next = dummy.next;
dummy.next = prev;
prev = dummy;
dummy = next;
c++;
}
if(dummy != null) {
head.next = reverse(dummy,k);
}
return prev;
}
}
首先,编写一个计算列表长度的方法。稍后,通过每次增加 c
.
稍后,与其在重复调用 reverse
方法之前检查 if (dummy != null
),不如检查列表中是否还有足够的元素 - 通过比较在以计数器开头。
我写一个辅助方法
private boolean areAtLeastNNodes(int n, Node head)
因此,在尝试反转任何东西之前,我会调用此方法。如果returns为假,我将弃权。
我自己的 areAtLeastNNodes()
版本是递归的,因为我觉得它更简单。它也可以是迭代的。
我的建议是对每个子列表传递两次,一次用于计数,一次用于反转。这感觉很浪费。这当然可以避免,但它会很复杂,我不想打扰。
使用递归不需要计算列表的长度。但是,指针操作有点棘手。
public static Node reverseK(Node head, int k)
{
return reverseK(head, head, k, k);
}
private static Node reverseK(Node head, Node node, int i, int k)
{
// we reached a final sequence of length < k, return the current head
if(node == null)
return head;
if(i == 1)
{
// we reached the end of a sequence of length k.
// Reverse the next sequence, return the new head.
head.next = reverseK(node.next, node.next, k, k);
return node;
}
// Store current next as it will be modified by the recursive call.
Node next = node.next;
Node newHead = reverseK(head, node.next, i-1, k);
// If the current sequence was of length k, reverse pointers.
if(newHead != head)
{
next.next = node;
}
return newHead;
}
测试:
int[] a = {1, 2, 3, 4, 5};
Node head = build(a);
print(head);
head = reverseK(head, 3);
print(head);
输出:
1 2 3 4 5
3 2 1 4 5
我会考虑使用模数 k 的方法。在迭代的每一步,当前节点都可以从函数调用者或递归调用的结果中获取其“下一个”字段的值。
Python代码:
def print_list(node, k):
i = 0
s = ""
while node:
s += node['val']
node = get_next(node)
if i == k - 1:
s += " "
i = (i + 1) % k
print(s)
def get_next(node):
return node['next']
def set_next(node, new_next):
node['next'] = new_next
# Returns (this_block_head, next_block_head)
def reverse(node, k, new_next=None, m=0):
if k == 1:
return (node, None)
# We use 'this_block_head' as a signal
# that when returns this current node,
# it means the block's length is less than
# k, and therefore will not be reversed.
if not node:
return (None, None) if m == 0 else (new_next, None)
# The first node in
# a block doesn't get
# a next parameter and
# must get it from the
# recursive call.
next_param = None if m == k - 1 else node
(this_block_head, next_block_head) = reverse(get_next(node), k, next_param, (m + 1) % k)
if this_block_head == node:
# When 'new_next' is null,
# this is a beginning of a block
# so the caller needs the node
# as its 'this_block_head'.
return (new_next if new_next else node, None)
# The last in the block,
# which will become first,
# here 'this_block_head' is
# actually 'next_block_head'
if m == k - 1:
set_next(node, new_next)
return (node, this_block_head)
set_next(node, next_block_head if m == 0 else new_next)
return (this_block_head, next_block_head)
输出:
def reset_list():
global a, b, c, d, e, f
f = {'val': 'f', 'next': None}
e = {'val': 'e', 'next': f}
d = {'val': 'd', 'next': e}
c = {'val': 'c', 'next': d}
b = {'val': 'b', 'next': c}
a = {'val': 'a', 'next': b}
reset_list()
print_list(a, 6) # abcdef
reverse(a, 2)
print_list(b, 2) # ba dc fe
print("")
reset_list()
print_list(a, 6) # abcdef
reverse(a, 3)
print_list(c, 3) # cba fed
print("")
reset_list()
print_list(a, 6) # abcdef
reverse(a, 4)
print_list(d, 4) # dcba ef
你可以这样做,
对于以下示例,您将收到此回复
4 -> 3 -> 2 -> 1 -> 5 -> 6
public class Main {
public static void main(String[] args) {
Node n1 = new Node(1);
Node n2 = new Node(2);
Node n3 = new Node(3);
Node n4 = new Node(4);
Node n5 = new Node(5);
Node n6 = new Node(6);
n1.next = n2;
n2.next = n3;
n3.next = n4;
n4.next = n5;
n5.next = n6;
System.out.println(reverse(n1, n1, n1.next, 4));
}
public static Node reverse(Node fst, Node lst, Node nxt, int k) {
if (k == 1) {
return fst;
} else {
Node m1 = fst;
Node m2 = nxt.next;
fst = nxt;
fst.next = m1;
lst.next = m2;
return reverse(fst, lst, lst.next, --k);
}
}
}
class Node {
public int val;
public Node next;
public Node(int val) {
this.val = val;
}
@Override
public String toString() {
if (next == null) {
return "" + val;
} return val + " -> " + next.toString();
}
}