我最近遇到了一个算法问题:
将单链表以k个元素为一组进行原地反转。首选迭代方法。 结果列表的第一个块应该是相对于k来说最大的。如果链表包含n个元素,则最后一个块要么是完整的,要么包含n mod k个元素。
For example:
k = 2, list = [1,2,3,4,5,6,7,8,9], the reversed list is [8,9,6,7,4,5,2,3,1]
k = 3, list = [1,2,3,4,5,6,7,8,9], the reversed list is [7,8,9,4,5,6,1,2,3]
我的代码如下所示。
是否有一种不使用栈或额外空间的 O(n) 算法?
public static ListNode reverse(ListNode list, int k) {
Stack<ListNode> stack = new Stack<ListNode>();
int listLen = getLen(list);
int firstBlockSize = listLen % k;
ListNode start = list;
if (firstBlockSize != 0) {
start = getBlock(stack, start, firstBlockSize);
}
int numBlock = (listLen) / k;
for (int i = 0; i < numBlock; i++) {
start = getBlock(stack, start, k);
}
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
while (!stack.empty()) {
cur.next = stack.peek();
cur = stack.pop();
while (cur.next != null) {
cur = cur.next;
}
}
return dummy.next;
}
public static ListNode getBlock(Stack<ListNode> stack, ListNode start, int blockSize) {
ListNode end = start;
while (blockSize > 1) {
end = end.next;
blockSize--;
}
ListNode temp = end.next;
end.next = null;
stack.push(start);
return temp;
}
public static int getLen(ListNode list) {
ListNode iter = list;
int len = 0;
while (iter != null) {
len++;
iter = iter.next;
}
return len;
}
A->B->C->D->E
变成([]
表示这里的指针)[A]->[B]->[C]->D->E
(前三个元素的指针),变成[A]<-[B] [C]->D->E
此时我们停止指向A并开始指向D,所以A<-[B] [C]->[D]
现在我们将C指向B,所以A<-[B]<-[C] [D]->E
此时我们将指针从B移动到E(就像我们用A到D一样),得到A<-B<-[C] [D]->[E]
现在再次A<-B<-[C]<-[D] [E]
,由于E是最后一个,我们将其作为头部并执行A<-B<-C<-D<-E
,完成了。 - Benjamin Gruenbaum