링크 된 목록의 헤드가 제공되고 모든 k 개의 노드 순서를 역순으로 요청할 경우 Java에서이 작업을 어떻게 수행 할 수 있습니까? 예 : k = 3 인 a->b->c->d->e->f->g->h
은 c->b->a->f->e->d->h->g->f
Java : 청크로 된 LinkedList 역전
일 것입니다. 일반적인 도움말이나 의사 코드도 크게 감사하겠습니다. 감사!
링크 된 목록의 헤드가 제공되고 모든 k 개의 노드 순서를 역순으로 요청할 경우 Java에서이 작업을 어떻게 수행 할 수 있습니까? 예 : k = 3 인 a->b->c->d->e->f->g->h
은 c->b->a->f->e->d->h->g->f
Java : 청크로 된 LinkedList 역전
일 것입니다. 일반적인 도움말이나 의사 코드도 크게 감사하겠습니다. 감사!
k
이 상당히 작을 것으로 예상되는 경우 가장 단순한 것으로 간주합니다. 링크 된 목록이라는 사실을 무시하고 각 하위 시퀀스를 역순으로 배열 형식의 것으로 처리합니다.
따라서 링크 된 목록의 노드 클래스가 Node<T>
이면 크기 (k
)를 만듭니다. 각 세그먼트에 대해 k
Nodes
을 배열 목록에로드 한 다음 간단한 for
루프로 요소를 반대로 만듭니다. 의사 코드에서 :
장점 : 매우 간단하고 O (N) 성능은 쉽게 인식 할 수있는 역방향 알고리즘을 이용합니다.
단점 :
는 또한이 각 Node
목록으로 이동하지 않는다는 것을 의미 있습니다 (당신이 세그먼트 당 재사용 할 수 있기 때문에, 한 번만)를 k
2N 크기 배열이 필요 만있는 오브젝트 Node
는 보유 . 즉, 각 Node
은 이전에 보유한 것과 다른 항목을 보유하게됩니다. 귀하의 필요에 따라 이것은 좋을 수도 있고 그렇지 않을 수도 있습니다.
Erm 물론 두 노드 (노드 및 모두)의 교체도 수행 할 수 있습니다. 그것은 내가 하키를 보면서 응답하는 것입니다 ... – yshavit
k가 작지 않은 경우는 어떨까요? 문제는 O (n) 시간 및 O (1) 공간의 적절한 위치에서 해결할 수 있습니다. 내 솔루션을 참조 – kasavbere
@ kasavbere 그래, 확실히 될 수 있습니다.당신의 솔루션은 좀 더 복잡합니다. 그래서 k가 작다고 알려져 있다면 (어떤 소스에서든지 함수의 req가 나온 곳에서) k가 작다는 것을 알게되면 더 간단한 코드로 간다고 말할 것입니다. 하지만 당신은 그것이 제한적이라는 것이 옳다. 그래서 나는 그들을 명시 적으로 (두 번, 심지어는) 호출했다. – yshavit
이것은 꽤 높은 수준이지만, 몇 가지 지침을 줄 것이라고 생각합니다.
void swap3(Node first, Node last)
과 같은 도우미 메서드를 사용하면 목록의 임의의 위치에서 세 개의 요소를 가져 와서 되돌릴 수 있습니다. 이것은 어렵지 않아야하며 재귀 적으로 수행 될 수 있습니다 (외부 요소 교환, 목록의 크기가 0 또는 1이 될 때까지 내부 요소에서 반복). 이제 생각해 보면 재귀를 사용하는 경우 쉽게 swapK()
으로 일반화 할 수 있습니다.
일단 완료되면 연결된 목록을 따라 걸어서 k
노드마다 swapK()
(으)로 전화하면됩니다. 목록의 크기가 k
으로 나눌 수없는 경우 마지막 비트를 스왑하지 않거나 스와핑 기법을 사용하여 마지막 length%k
노드를 반대로 바꿀 수 있습니다.
TIME O (n); 공간 O (1)
목록 반전의 일반적인 요구 사항은 O (n) 시간 및 O (1) 공간에서 수행하는 것입니다. 이것은 재귀 또는 스택 또는 임시 배열 (K == n이면?) 등을 제거합니다. 그러므로 여기서의 도전 과제는 K
요소를 고려하여 내부 반전 알고리즘을 수정하는 것입니다. K
대신 거리로 dist
을 사용합니다.
다음은 간단한 반전 (in-place) 반전 알고리즘입니다. 세 개의 포인터를 사용하여 목록에서 적절한 위치로 이동하십시오. b
은 새 목록의 헤드를 가리 킵니다. c
은 처리되지 않은 목록의 이동 헤드를 가리 킵니다. b
과 c
사이의 스와핑을 용이하게하기 위해 a
.
A->B->C->D->E->F->G->H->I->J->L //original
A<-B<-C<-D E->F->G->H->I->J->L //during processing
^^
| |
b c
`a` is the variable that allow us to move `b` and `c` without losing either of
the lists.
Node simpleReverse(Node n){//n is head
if(null == n || null == n.next)
return n;
Node a=n, b=a.next, c=b.next;
a.next=null; b.next=a;
while(null != c){
a=c;
c=c.next;
a.next=b;
b=a;
}
return b;
}
가
chunkReverse
알고리즘에
simpleReverse
알고리즘을 전환하기 위해, 다음을 수행
1] 첫번째 청크를 반전 후 b
head
로 설정; head
은 결과 목록의 영구 헤드입니다.
2] 다른 모든 청크의 경우 tail.next
에서 b
으로 설정하십시오. b
은 방금 처리 된 청크의 헤드입니다.
다른 세부 사항 : 목록이 하나 개 더 적은 노드가 또는 DIST 1 이하인 경우는
3], 후 처리없이 목록을 반환한다.
4] 카운터 cnt
을 사용하여 dist
개의 연속 노드가 역전 된 시점을 추적합니다.
5] 방금 처리 된 청크의 꼬리를 추적하려면 tail
변수를 사용하고 처리중인 청크의 꼬리를 추적하려면 tmp
변수를 사용하십시오.
6] 청크가 처리되기 전에, 꼬리가 될 머리가 첫 번째 노드라는 사실에 주목하십시오. 즉, 임시 꼬리 인 tmp
으로 설정하십시오.
public Node reverse(Node n, int dist) {
if(dist<=1 || null == n || null == n.right)
return n;
Node tail=n, head=null, tmp=null;
while(true) {
Node a=n, b=a.right; n=b.right;
a.right=null; b.right=a;
int cnt=2;
while(null != n && cnt < dist) {
a=n; n=n.right; a.right=b; b=a;
cnt++;
}
if(null == head) head = b;
else {
tail.right=b;tail=tmp;
}
tmp=n;
if(null == n) return head;
if(null == n.right) {
tail.right=n;
return head;
}
}//true
}
첫 번째 알 고가 정확하다고 가정하면 역순으로 사용하십시오. – UmNyobe
'첫 번째 알 고가 맞다고 가정합니다 .'? 테스트하기 쉽습니다. 'insert','print' 그리고이'reverse' 함수로'int' LinkedList 클래스를 작성하십시오. 그리고 나서'main()'메쏘드에서'1에서 x = 26'까지 또는'int's로 목록을 채 웁니다. 그런 다음'dist '의 다른 값에 대해 역순으로 수행하십시오. '왜 그냥 역방향으로 사용하지 않으 시렵니까? '라는 말이 무슨 뜻인지 확실하지 않습니다. – kasavbere
'simpleReverse'가 한 인덱스 위치에서 다른 인덱스 위치로 역전되도록 (그리고 추가 포인터를 유지하면서) 수정한다는 것을 의미합니다. 리턴 된 마지막 포인터를 사용하여 다른 인덱스로 필요한만큼'simpleReverse'를 반복적으로 호출합니다. 그런 것 ... – UmNyobe
예 : 커먼 리스프
(defun rev-k (k sq)
(if (<= (length sq) k)
(reverse sq)
(concatenate 'list (reverse (subseq sq 0 k)) (rev-k k (subseq sq k)))))
다른 방법에 의해 일예 F에 의해 #은 스택
open System.Collections.Generic
let rev_k k (list:'T list) =
seq {
let stack = new Stack<'T>()
for x in list do
stack.Push(x)
if stack.Count = k then
while stack.Count > 0 do
yield stack.Pop()
while stack.Count > 0 do
yield stack.Pop()
}
|> Seq.toList
재귀가 너무 많은 공간을 사용합니다. 내 솔루션을 참조하십시오 – kasavbere
다음을 팝업과 장소에 추가 스택을 사용하여 반복적으로 목록에서 K 항목을 제거, 스택에 밀어 사용합니다. 최선의 해결책인지는 확실치 않지만 스택은 사물을 반전시키는 적절한 방법을 제공합니다. 대기열이있는 목록 대신이 기능이 작동합니다. 간단히 디큐 K 항목을 스택에 밀어 스택에서 그들을 팝업 대기열 :
재귀가 너무 많은 공간을 사용합니다. 내 솔루션 – kasavbere
이 구현은 반복자 클래스 사용
LinkedList<T> list;
//Inside the method after the method's parameters check
ListIterator<T> it = (ListIterator<T>) list.iterator();
ListIterator<T> reverseIt = (ListIterator<T>) list.listIterator(k);
for(int i = 0; i< (int) k/2; i++)
{
T element = it.next();
it.set(reverseIt.previous());
reverseIt.set(element);
}
너무 많은 공간을 참조하십시오. 내 솔루션보기 – kasavbere
도움이 재귀 것인가를? – Coffee
@ Adel 예! – OckhamsRazor
k = 3은 c → b → a → f → e → d → h → g 일 것입니다. – BLUEPIXY