programing

단일 연결 목록의 끝에서 n 번째 요소를 찾는 방법은 무엇입니까?

nasanasas 2020. 12. 7. 08:13
반응형

단일 연결 목록의 끝에서 n 번째 요소를 찾는 방법은 무엇입니까?


다음 함수는을 찾기 위해 노력 nth마지막 단일 연결리스트의 요소입니다.

예를 들면 :

요소가 있으면 마지막 노드에 8->10->5->7->2->1->5->4->10->10대한 결과는 7th입니다 7.

아무도이 코드가 작동하는 방식에 대해 나를 도울 수 있습니까? 아니면 더 좋고 간단한 접근 방식이 있습니까?

LinkedListNode nthToLast(LinkedListNode head, int n) {
  if (head == null || n < 1) {
    return null;
  }

  LinkedListNode p1 = head;
  LinkedListNode p2 = head;

  for (int j = 0; j < n - 1; ++j) { // skip n-1 steps ahead
    if (p2 == null) {
      return null; // not found since list size < n
    }
    p2 = p2.next;
  }

  while (p2.next != null) {
    p1 = p1.next;
    p2 = p2.next;
  }

  return p1;
}

알고리즘은 먼저 N 노드 떨어져있는 연결 목록의 두 노드에 대한 참조를 생성하여 작동합니다. 따라서 귀하의 예에서 N이 7이면 p1을 8로, p2를 4로 설정합니다.

그런 다음 p2가 목록의 마지막 요소에 도달 할 때까지 각 노드 참조를 목록의 다음 노드로 이동합니다. 다시, 귀하의 예에서 이것은 p1이 5이고 p2가 10 일 때입니다.이 시점에서 p1은 목록의 마지막 요소에 대해 N 번째 요소를 참조합니다 (N 노드 떨어져 있다는 속성에 의해).


이 알고리즘의 핵심은 두 개의 포인터 설정하는 것입니다 p1p2의해 떨어져을 n-1우리가 원하는, 그래서 처음 노드 p2받는 점에 (n-1)th우리가 이동 목록의 처음부터 노드 p2가 도달 할 때까지 last목록의 노드를. 일단 p2도달리스트 끝 p1리스트의 끝에서 n 번째 노드를 가리키는 것이다.

설명을 주석으로 삽입했습니다. 도움이되기를 바랍니다.

// Function to return the nth node from the end of a linked list.
// Takes the head pointer to the list and n as input
// Returns the nth node from the end if one exists else returns NULL.
LinkedListNode nthToLast(LinkedListNode head, int n) {
  // If list does not exist or if there are no elements in the list,return NULL
  if (head == null || n < 1) {
    return null;
  }

  // make pointers p1 and p2 point to the start of the list.
  LinkedListNode p1 = head;
  LinkedListNode p2 = head;

  // The key to this algorithm is to set p1 and p2 apart by n-1 nodes initially
  // so we want p2 to point to the (n-1)th node from the start of the list
  // then we move p2 till it reaches the last node of the list. 
  // Once p2 reaches end of the list p1 will be pointing to the nth node 
  // from the end of the list.

  // loop to move p2.
  for (int j = 0; j < n - 1; ++j) { 
   // while moving p2 check if it becomes NULL, that is if it reaches the end
   // of the list. That would mean the list has less than n nodes, so its not 
   // possible to find nth from last, so return NULL.
   if (p2 == null) {
       return null; 
   }
   // move p2 forward.
   p2 = p2.next;
  }

  // at this point p2 is (n-1) nodes ahead of p1. Now keep moving both forward
  // till p2 reaches the last node in the list.
  while (p2.next != null) {
    p1 = p1.next;
    p2 = p2.next;
  }

   // at this point p2 has reached the last node in the list and p1 will be
   // pointing to the nth node from the last..so return it.
   return p1;
 }

또는 대신 n 노드로 설정 p1하고 p2분리 한 (n-1)다음 p2마지막 노드까지 이동하는 대신 목록의 끝까지 이동할 수 있습니다 .

LinkedListNode p1 = head;
LinkedListNode p2 = head;
for (int j = 0; j < n ; ++j) { // make then n nodes apart.
    if (p2 == null) {
        return null;
    }
    p2 = p2.next;
}
while (p2 != null) { // move till p2 goes past the end of the list.
    p1 = p1.next;
    p2 = p2.next;
}
return p1;

이 접근 방식에 대해 어떻게 생각하십니까?

  1. 연결 목록의 길이를 계산합니다.
  2. 헤드의 실제 노드 인덱스 = 링크 된 목록 길이-주어진 인덱스;
  3. 헤드에서 순회하는 함수를 작성하고 위의 인덱스에서 노드를 가져옵니다.

//this  is the recursive solution


//initial call
find(HEAD,k);

// main function
void find(struct link *temp,int k)
{  
 if( temp->next != NULL)
   find( temp->next, k);
 if((c++) == k)       // c is initially declared as 1 and k is the node to find from last.
  cout<<temp->num<<' ';
}

여기에는 이미 많은 답변이 있지만 모두 목록을 두 번 (순차적으로 또는 병렬로) 살펴 보거나 많은 추가 스토리지를 사용합니다.

일정한 추가 공간을 사용하여 목록을 한 번만 (그리고 조금 더) 걷는 동안 이렇게 할 수 있습니다.

Node *getNthFromEnd(Node *list, int n) {

    if (list == null || n<1) {
        return null; //no such element
    }

    Node *mark1 = list, *mark2 = list, *markend = list;
    int pos1 = 0, pos2 = 0, posend = 0;

    while (markend!=null) {
        if ((posend-pos2)>=(n-1)) {
            mark1=mark2;
            pos1=pos2;
            mark2=markend;
            pos2=posend;
        }
        markend=markend->next;
        ++posend;
    }
    if (posend<n) {
        return null; //not enough elements in the list
    }

    //mark1 and mark2 are n-1 elements apart, and the end is at least
    //1 element after mark2, so mark1 is at least n elements from the end

    while((posend - pos1) > n) {
      mark1 = mark1->next;
      ++pos1;
    }
    return mark1;
}

이 버전은 N+n순회 보다 적은 2 개의 추가 포인터를 사용합니다. 여기서은 N목록의 길이이고 n인수입니다.

M추가 포인터 를 사용하는 경우 아래로 내려갈 수 있습니다 N+ceil(n/(M-1))(원형 버퍼에 저장해야 함).


이것은 숙제처럼 들리기 때문에 실제 해결책을 제시하는 대신 스스로 도와주는 것을 선호합니다.

작은 샘플 데이터 세트에서이 코드를 실행하는 것이 좋습니다. 디버거를 사용하여 줄을 단계별로 실행합니다 (함수 시작시 중단 점을 설정할 수 있음). 이것은 코드가 어떻게 작동하는지에 대한 아이디어를 제공 할 것입니다.

Console.WriteLine()관심있는 변수를 출력 할 수도 있습니다 .


이 문제에 대한 또 다른 해결책입니다. 시간 복잡도는 동일하지만이 코드는 단일 루프에서 솔루션을 달성합니다.

public Link findKthElementFromEnd(MyLinkedList linkedList, int k)
    {
        Link current = linkedList.getFirst();//current node
        Link currentK = linkedList.getFirst();//node at index k

        int counter = 0;

        while(current.getNext()!=null)
        {
            counter++;

            if(counter>=k)
            {
                currentK = currentK.getNext();
            }

            current = current.getNext();
        }

        //reached end
        return currentK;
    }

선형 시간에서 연결된 목록을 반대로하고 k 번째 요소를 찾으십시오. 여전히 선형 시간으로 실행됩니다.


연결 목록을 반복하고 크기를 얻을 수 있습니다. 일단 크기가 있으면 2n에서 n 번째 항을 찾을 수 있습니다. 이것은 여전히 ​​O (n)입니다.

public T nthToLast(int n) {
    // return null if linkedlist is empty
    if (head == null) return null;

    // declare placeholder where size of linkedlist will be stored
    // we are hoping that size of linkedlist is less than MAX of INT
    int size = 0;

    // This is O(n) for sure
    Node i = head;
    while (i.next != null) {
        size += 1;
        i = i.next;
    }

    // if user chose something outside the size of the linkedlist return null
    if (size < n)
        return null;

    // This is O(n) if n == size
    i = head;
    while(size > n) {
        size--;
        i = i.next;
    }

    // Time complexity = n + n = 2n
    // therefore O(n)

    return i.value;
}

C #의 솔루션. 더미 값으로 LinkedList를 만듭니다.

  LinkedList<int> ll = new LinkedList<int>();
            ll.AddFirst(10);
            ll.AddLast(12);
            ll.AddLast(2);
            ll.AddLast(8);
            ll.AddLast(9);
            ll.AddLast(22);
            ll.AddLast(17);
            ll.AddLast(19);
            ll.AddLast(20);

첫 번째 노드를 가리키는 2 개의 포인터 p1 및 p1을 만듭니다.

        private static bool ReturnKthElement(LinkedList<int> ll, int k)
        {
            LinkedListNode<int> p1 = ll.First;
            LinkedListNode<int> p2 = ll.First;

p2가 null이 될 때까지 루프를 반복합니다. 즉, 링크 된 목록 길이가 K 번째 요소보다 작거나 K 번째 요소까지입니다.

            for (int i = 0; i < k; i++)
            {
                p2 = p2.Next;
                if (p2 == null)
                {
                    Console.WriteLine($"Linkedlist is smaller than {k}th Element");
                    return false;
                }
            }

이제 p2가 null이 될 때까지 두 포인터를 반복합니다. p1 포인터에 포함 된 값은 K 번째 요소에 해당합니다.


            while (p2 != null)
            {
                p1 = p1.Next;
                p2 = p2.Next;
            }
            //p1 is the Kth Element
            Console.WriteLine($"Kth element is {p1.Value}");
            return true;
        }

여기 StackOverflow의 다른 스레드에 재귀 솔루션이 있습니다.


아니요, 링크드리스트의 길이를 모릅니다. 좋아요 목록의 길이를 얻으려면 한 번만 거쳐야하므로 접근 방식이 비효율적입니다.


여기서 우리는 두 개의 포인터 pNode와 qNode를 취합니다. 그런 다음 목록 끝까지 트래버스하면 개수와 위치 사이의 차이가 0보다 크고 pthNode가 각 루프에서 한 번씩 증가 할 때만 pNode가 트래버스합니다.

static ListNode nthNode(int pos){
ListNode pNode=head;
ListNode qNode=head;
int count =0;
while(qNode!=null){
    count++;
    if(count - pos > 0)
        pNode=pNode.next;
    qNode=qNode.next;
}
return pNode;
}

public int nthFromLast(int n){
    Node current = head;
    Node reference = head;      
    for(int i=0;i<n;i++){
        reference=reference.getNext();
    }
    while(reference != null){
        current = current.getNext();
        reference = reference.getNext();
    }
    return current.getData();
}

두 개의 포인터 pTemp 및 NthNode를 사용하십시오. 처음에는 둘 다 목록의 헤드 노드를 가리 킵니다. NthNode는 pTemp가 n 개 이동 한 후에 만 ​​이동을 시작합니다. 둘 다에서 pTemp가 목록 끝에 도달 할 때까지 앞으로 이동합니다. 결과적으로 NthNode는 연결 목록의 끝에서 n 번째 노드를 가리 킵니다.

public ListNode NthNodeFromEnd(int n){
    ListNode pTemp = head, NthNode = null;
   for(int count=1; count<n;count++){
     if(pTemp!=null){
       pTemp = pTemp.getNext();
     }
   }
   while(pTemp!=null){
     if(NthNode==null){
         NthNode = head;
     }
     else{
        NthNode = NthNode.getNext();
     }
     pTemp = pTemp.getNext();
   }
   if(NthNode!=null){
     NthNode = NthNode.getNext();
     return NthNode;
   }
return null;
}

TextBook : "자바로 쉽게 만든 데이터 구조 및 알고리즘"참조


이 문제를 이해하려면 측정 예를 사용하여 간단한 비유를해야합니다. 중지에서 정확히 1 미터 떨어진 팔의 위치를 ​​찾아야한다고 가정 해 보겠습니다. 어떻게 측정 하시겠습니까? 1 미터 길이의 눈금자를 잡고 그 눈금자의 상단을 가운데 손가락 끝에 놓으면 미터의 하단이 가운데 상단에서 정확히 1 미터 떨어져 있습니다. 손가락.

이 예제에서 우리가하는 일은 똑같을 것입니다. 우리는 단지 n- 요소 폭을 가진 프레임이 필요하고 우리가해야 할 일은 프레임을 목록의 끝에 놓는 것입니다. 따라서 프레임의 시작 노드는 정확히 n- 목록의 끝에 th 요소.

이것은 목록에 M 개의 요소가 있고 N 개의 요소 폭이있는 프레임을 가정 한 목록입니다.

HEAD -> EL(1) -> EL(2) -> ... -> EL(M-1) -> EL(M)

<-- Frame -->

그러나 프레임의 경계 만 필요하므로 프레임의 끝 경계는 프레임의 시작 경계에서 정확히 떨어진 요소 (N-1)가됩니다. 따라서 이러한 경계 요소 만 저장해야합니다. 그들을 A와 B라고 부르 자.

HEAD -> EL(1) -> EL(2) -> ... -> EL(M-1) -> EL(M)

A <- N-Element Wide-> B

가장 먼저해야 할 일은 프레임의 끝인 B를 찾는 것입니다.

ListNode<T> b = head;
int count = 1;

while(count < n && b != null) {
    b = b.next;
    count++;
}

이제 b 는 배열의 n 번째 요소이고 aHEAD에 있습니다. 그래서 우리의 프레임이 설정되고, 우리가 할 일은 b 가 목록의 끝에 도달 할 때까지 두 경계 노드를 단계적으로 증가 시키는 것입니다. 여기서 a 는 마지막 요소에서 n 번째 요소가됩니다.

ListNode<T> a = head;

while(b.next != null) {
    a = a.next;
    b = b.next;
}

return a;

모든 것을 모으고 HEAD 검사로 N <M (여기서 M은 목록의 크기) 검사 및 기타 항목을 수집하려면 여기에 완전한 솔루션 방법이 있습니다.

public ListNode<T> findNthToLast(int n) {
    if(head == null) {
        return null;
    } else {
        ListNode<T> b = head;
        int count = 1;

        while(count < n && b != null) {
            b = b.next;
            count++;
        }

        if(count == n && b!=null) {
            ListNode<T> a = head;

            while(b.next != null) {
                a = a.next;
                b = b.next;
            }

            return a;
        } else {
            System.out.print("N(" + n + ") must be equal or smaller then the size of the list");
            return null;
        }
    }
}

위의 문제는 해시 테이블을 사용하여 해결할 수도 있는데 해시 테이블의 항목은 노드의 위치와 노드의 주소입니다. 따라서 끝에서 n 번째 노드를 찾으려면 (이는 m이 노드의 수인 첫 번째에서 m-n + 1을 의미합니다) 이제 해시 테이블 항목을 입력 할 때 노드의 수를 얻습니다.

1. 각 노드를 탐색하고 해시 테이블에 해당 항목을 만듭니다.

2. 해시 테이블에서 m-n + 1 노드를 찾아 주소를 얻습니다.

시간 복잡도는 O (n)입니다.


나는 질문 코드에 한 가지 결함이 있다고 생각하고, 이것이 어떻게 가능한지 책에서 가져온 것인지 궁금합니다. 올바르게 실행될 수 있지만 코드는 논리적으로 다소 잘못되었습니다. for 루프 내부에서 ... if 조건을 확인해야합니다.p2->next ! = NULL

 for (int j = 0; j < n - 1; ++j) { // skip n-1 steps ahead
       if (p2->next == null) {
       return null; // not found since list size < n
   }

... 휴식은 괜찮고 설명이 이미 주어진 것처럼 코드 이동 p2 (n-1)위치가으로 진행된 p1다음 while 루프 p2->next에서 끝까지 동시에 이동합니다 .


커리어 컵 북에 주어진 문제는 약간 다릅니다. 단일 연결 목록의 n 번째부터 마지막 ​​요소를 찾습니다.

내 코드는 다음과 같습니다.

    public void findntolast(int index)
    {
        Node ptr = front; int count = 0;
        while(ptr!=null)
        {
            count++;
            if (count == index)
            {
                front = ptr;
                break;
            }
            ptr = ptr.next;
        }
        Node temp=front;
        while(temp!=null)
        {
            Console.WriteLine(temp.data);
            temp=temp.next;
        }
    }

재귀 솔루션 :

Node findKth (Node head, int count, int k) {
    if(head == null)
        return head;
    else {
        Node n =findKth(head.next,count,k);
        count++;

        if(count == k)
            return head;

        return n;
    }
}

추가 데이터 구조를 사용할 수 있습니까? .. 간단하다면 ... 모든 노드를 스택에 밀어 넣고 카운터를 유지하십시오. 귀하의 예에 따라 8-> 10-> 5-> 7-> 2-> 1-> 5-> 4-> 10-> 10 링크 목록 읽기를 시작하고 노드 또는 노드-> 데이터를 스택. 따라서 스택은 top-> {10, 10,4, 5, 1, 2, 7, 5, 10, 8} <-bottom처럼 보일 것입니다.

이제 카운터 1을 유지하면서 스택의 맨 위에서 터지기 시작하고 팝업 할 때마다 카운터를 1 씩 늘리고 n 번째 요소 (예 : 7 번째 요소)에 도달하면 터지는 것을 중지합니다.

참고 : 이것은 데이터 / 노드를 역순으로 인쇄하거나 검색합니다.


(다음은 2 포인터 접근 방식을 사용하여 코드 소스 )

느리고 빠른 포인터 접근

struct node
{
  int data;
  struct node *next;
}mynode;


mynode * nthNodeFrmEnd(mynode *head, int n /*pass 0 for last node*/)
{
  mynode *ptr1,*ptr2;
  int count;

  if(!head)
  {
    return(NULL);
  }

  ptr1  = head;
  ptr2  = head;
  count = 0;

  while(count < n)
  {
     count++;
     if((ptr1=ptr1->next)==NULL)
     {
        //Length of the linked list less than n. Error.
        return(NULL);
     }
  }

  while((ptr1=ptr1->next)!=NULL)
  {
    ptr2=ptr2->next;
  }

  return(ptr2);
}


재귀

node* findNthNode (node* head, int find, int& found){
    if(!head) {
        found = 1;
        return 0;
    }
    node* retval = findNthNode(head->next, find, found);
    if(found==find)
        retval = head;
    found = found + 1;
    return retval;
}


내 접근 방식은 간단하고 시간 복잡성 O (n)이 있다고 생각합니다.

1 단계 : 먼저 노드 수를 가져옵니다. 첫 번째 노드에서 마지막 노드까지 for 루프 실행

2 단계 : 개수가 있으면 간단한 수학을 적용합니다. 예를 들어 마지막 노드에서 7 번째 노드를 찾았고 모든 노드의 개수가 12이면 (count-index) -1은 k 번째 노드를 제공합니다. 트래버스해야하며 마지막 노드의 n 번째 노드가됩니다. 이 경우 (12-7) -1 = 4

요소가 8-> 10-> 5-> 7-> 2-> 1-> 5-> 4-> 10-> 10이면 7 번째에서 마지막 노드까지의 결과는 7입니다. 시작.


Java에서는 다음을 사용할 것입니다.

public class LL {
  Node head;
  int linksCount;

   LL(){
     head = new Node();
     linksCount = 0;
   }

  //TRAVERSE TO INDEX
  public Node getNodeAt(int index){
    Node temp= head;
    if(index > linksCount){
        System.out.println("index out of bound !");
        return null;
    }
    for(int i=0;i<index && (temp.getNext() != null);i++){
        temp = temp.getNext();
    }
    return temp.getNext();
  }
}

n이 LinkedList의 길이보다 크면 Jonathan의 버전이 NullPinterException을 던지는 것을 아무도 알아 차리지 못했습니다. 내 버전은 다음과 같습니다.

public Node nth(int n){
        if(head == null || n < 1) return null;

        Node n1 = head;
        Node n2 = head;
        for(int i = 1; i < n; i++){
            if(n1.next == null) return null; 
            n1 = n1.next;
        }

        while (n1.next != null){
            n1 = n1.next;
            n2 = n2.next;
        }
        return n2;
}

여기서는 약간 변경합니다. 노드 n1이 앞으로 나아갈 때 n1이 null인지 확인하는 대신 날씨 n1.next가 null인지 확인하거나 while 루프 n1.next에서 NullPinterException이 발생하는지 확인합니다.


다음은 Linklist에서 n 번째 자식을 찾는 C # 버전입니다.

public Node GetNthLast(Node head, int n)
    {
        Node current, nth;
        current = nth = head;
        int counter = 0;

        while (current.next != null)
        {
            counter++;
            if (counter % n == 0)
            {
                for (var i = 0; i < n - 1; i++)
                {
                    nth = nth.next;
                }
            }
            current = current.next;
        }
        var remainingCounts = counter % n;
        for (var i = 0; i < remainingCounts; i++)
        {
            nth = nth.next;
        }
        return nth;
    }

메모리 비용 허용 오차 (이 솔루션의 O (k))에 따라 길이 k의 포인터 배열을 할당하고 연결된 목록을 순회하면서 노드를 원형 배열로 채울 수 있습니다.

연결 목록 순회를 마치면 배열의 첫 번째 요소 (원형 배열이므로 0 인덱스를 올바르게 계산해야 함)에 대한 답을 얻을 수 있습니다.

배열의 첫 번째 요소가 null이면 문제에 대한 해결책이 없습니다.



가장 먼저

의견에서 언급했듯이 더 명확하게 질문은 다음과 같습니다.

<Cracking the coding interview 6th>| IX Interview Questions| 2. Linked Lists| Question 2.2.

Gayle Laakmann McDowell많은 사람들을 인터뷰 한 Google의 소프트웨어 엔지니어 인의 훌륭한 책 입니다.


구혼

(연결된 목록이 길이를 추적하지 않는다고 가정) , O (n) 시간과 O (1) 공간 에는 두 가지 접근 방식이 있습니다 .

  • 먼저 길이를 찾은 다음 (len-k + 1) 요소로 반복합니다.
    이 솔루션은 내가 기억하는 것처럼 책에 언급되지 않았습니다.
  • 두 포인터를 통해 루프 (k-1) 거리를 유지합니다.
    이 솔루션은 질문에서와 마찬가지로 책에서 가져온 것입니다.

암호

다음은 Java단위 테스트 를 사용하는 의 구현입니다 (JDK 자체에서 고급 데이터 구조를 사용하지 않음) .

KthToEnd.java

/**
 * Find k-th element to end of singly linked list, whose size unknown,
 * <p>1-th is the last, 2-th is the one before last,
 *
 * @author eric
 * @date 1/21/19 4:41 PM
 */
public class KthToEnd {
    /**
     * Find the k-th to end element, by find length first.
     *
     * @param head
     * @param k
     * @return
     */
    public static Integer kthToEndViaLen(LinkedListNode<Integer> head, int k) {
        int len = head.getCount(); // find length,

        if (len < k) return null; // not enough element,

        return (Integer) head.getKth(len - k).value; // get target element with its position calculated,
    }

    /**
     * Find the k-th to end element, via 2 pinter that has (k-1) distance.
     *
     * @param head
     * @param k
     * @return
     */
    public static Integer kthToEndVia2Pointer(LinkedListNode<Integer> head, int k) {
        LinkedListNode<Integer> p0 = head; // begin at 0-th element,
        LinkedListNode<Integer> p1 = head.getKth(k - 1); // begin at (k-1)-th element,

        while (p1.next != null) {
            p0 = p0.next;
            p1 = p1.next;
        }

        return p0.value;
    }

    static class LinkedListNode<T> {
        private T value;
        private LinkedListNode next;

        public LinkedListNode(T value) {
            this.value = value;
        }

        /**
         * Append a new node to end.
         *
         * @param value
         * @return new node
         */
        public LinkedListNode append(T value) {
            LinkedListNode end = getEnd();
            end.next = new LinkedListNode(value);
            return end.next;
        }

        /**
         * Append a range of number, range [start, end).
         *
         * @param start included,
         * @param end   excluded,
         */
        public void appendRangeNum(Integer start, Integer end) {
            KthToEnd.LinkedListNode last = getEnd();
            for (int i = start; i < end; i++) {
                last = last.append(i);
            }
        }

        /**
         * Get end element of the linked list this node belongs to, time complexity: O(n).
         *
         * @return
         */
        public LinkedListNode getEnd() {
            LinkedListNode end = this;
            while (end != null && end.next != null) {
                end = end.next;
            }

            return end;
        }

        /**
         * Count of element, with this as head of linked list.
         *
         * @return
         */
        public int getCount() {
            LinkedListNode end = this;
            int count = 0;
            while (end != null) {
                count++;
                end = end.next;
            }

            return count;
        }

        /**
         * Get k-th element from beginning, k start from 0.
         *
         * @param k
         * @return
         */
        public LinkedListNode getKth(int k) {
            LinkedListNode<T> target = this;
            while (k-- > 0) {
                target = target.next;
            }

            return target;
        }
    }
}

KthToEndTest.java

(단위 테스트,를 사용 TestNG하거나 JUnit원하는대로 / ..로 변경 )

import org.testng.Assert;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

/**
 * KthToEnd test.
 *
 * @author eric
 * @date 1/21/19 5:20 PM
 */
public class KthToEndTest {
    private int len = 10;
    private KthToEnd.LinkedListNode<Integer> head;

    @BeforeClass
    public void prepare() {
        // prepare linked list with value [0, len-1],
        head = new KthToEnd.LinkedListNode(0);
        head.appendRangeNum(1, len);
    }

    @Test
    public void testKthToEndViaLen() {
        // validate
        for (int i = 1; i <= len; i++) {
            Assert.assertEquals(KthToEnd.kthToEndViaLen(head, i).intValue(), len - i);
        }
    }

    @Test
    public void testKthToEndVia2Pointer() {
        // validate
        for (int i = 1; i <= len; i++) {
            Assert.assertEquals(KthToEnd.kthToEndVia2Pointer(head, i).intValue(), len - i);
        }
    }
}

팁 :

  • KthToEnd.LinkedListNode
    이것은 처음부터 구현 된 단순한 단일 연결 목록 노드이며, 연결 목록 자체에서 시작을 나타냅니다.
    머리 / 꼬리 / 길이를 추가로 추적하지는 않지만 방법이 있습니다.

참고URL : https://stackoverflow.com/questions/2598348/how-to-find-nth-element-from-the-end-of-a-singly-linked-list

반응형