ค้นหาองค์ประกอบที่เล็กที่สุด kth ในโครงสร้างการค้นหาแบบไบนารีด้วยวิธีที่เหมาะสมที่สุด


112

ฉันต้องการค้นหาองค์ประกอบที่เล็กที่สุด kth ในโครงสร้างการค้นหาไบนารีโดยไม่ต้องใช้ตัวแปรคงที่ / ทั่วโลก จะบรรลุอย่างมีประสิทธิภาพได้อย่างไร? วิธีแก้ปัญหาที่ฉันคิดไว้คือการดำเนินการใน O (n) ซึ่งเป็นกรณีที่เลวร้ายที่สุดเนื่องจากฉันวางแผนที่จะทำการลัดเลาะตามลำดับของต้นไม้ทั้งหมด แต่ลึก ๆ แล้วฉันรู้สึกว่าไม่ได้ใช้คุณสมบัติ BST ที่นี่ วิธีแก้ปัญหาสมมติของฉันถูกต้องหรือมีวิธีที่ดีกว่านี้หรือไม่?


7
ต้นไม้มีความสมดุลหรือไม่?
kennytm

มันไม่ใช่. แต่ถ้ามันสมดุลมีวิธีที่ดีที่สุดหรือไม่?
bragboy

1
หากคุณค้นหา "สถิติการสั่งซื้อ" คุณจะพบสิ่งที่คุณต้องการ
RAL

ฉันรู้สึกว่าคำตอบส่วนใหญ่ด้านล่างในขณะที่ถูกต้องคือการโกงเนื่องจากพวกเขากำลังใช้ตัวแปรส่วนกลางบางประเภท (ไม่ว่าจะเป็นการอ้างอิงถึงจำนวนเต็มหรือตัวแปรที่ลดลงและส่งคืน) หากไม่ได้รับอนุญาตอย่างแน่นอนฉันจะใช้การเรียกซ้ำโดยไม่มีการอ้างอิงใด ๆ
Henley Chiu

คำตอบ:


170

นี่เป็นเพียงโครงร่างของแนวคิด:

ใน BST ที่ทรีย่อยทางด้านซ้ายของโหนดมีองค์ประกอบเพียงน้อยกว่าค่าที่เก็บไว้ในT Tหากkมีขนาดเล็กกว่าจำนวนองค์ประกอบในทรีย่อยด้านซ้ายkองค์ประกอบที่เล็กที่สุดจะต้องเป็นของทรีย่อยด้านซ้าย มิฉะนั้นหากkมีขนาดใหญ่กว่าkองค์ประกอบที่เล็กที่สุดจะอยู่ในแผนผังย่อยด้านขวา

เราสามารถเพิ่ม BST เพื่อให้แต่ละโหนดเก็บจำนวนองค์ประกอบไว้ในทรีย่อยด้านซ้าย (สมมติว่าทรีย่อยด้านซ้ายของโหนดที่ระบุมีโหนดนั้น) ด้วยข้อมูลชิ้นนี้มันง่ายมากที่จะสำรวจต้นไม้โดยการขอจำนวนองค์ประกอบในทรีย่อยด้านซ้ายซ้ำ ๆ เพื่อตัดสินใจว่าจะเรียกคืนในทรีย่อยทางซ้ายหรือขวา

ตอนนี้สมมติว่าเราอยู่ที่โหนด T:

  1. ถ้าk == num_elements (ทรีย่อยด้านซ้ายของ T)Tแล้วคำตอบที่เรากำลังมองหาค่าอยู่ในโหนด
  2. ถ้าk> num_elements (แผนผังย่อยด้านซ้ายของ T)เห็นได้ชัดว่าเราสามารถเพิกเฉยต่อทรีย่อยด้านซ้ายได้เนื่องจากองค์ประกอบเหล่านั้นจะมีขนาดเล็กกว่าที่kเล็กที่สุด ดังนั้นเราจึงลดปัญหาในการค้นหาk - num_elements(left subtree of T)องค์ประกอบที่เล็กที่สุดของทรีย่อยที่เหมาะสม
  3. ถ้าk <num_elements (ทรีย่อยด้านซ้ายของ T)แล้วสิ่งที่kเล็กที่สุดจะอยู่ที่ไหนสักแห่งในทรีย่อยด้านซ้ายดังนั้นเราจึงลดปัญหาในการค้นหาkองค์ประกอบที่เล็กที่สุดในทรีย่อยด้านซ้าย

การวิเคราะห์ความซับซ้อน:

สิ่งนี้ต้องใช้O(depth of node)เวลาซึ่งเป็นO(log n)กรณีที่เลวร้ายที่สุดสำหรับ BST ที่สมดุลหรือO(log n)โดยเฉลี่ยสำหรับ BST แบบสุ่ม

BST ต้องการO(n)พื้นที่จัดเก็บและต้องใช้อีกอย่างO(n)ในการจัดเก็บข้อมูลเกี่ยวกับจำนวนองค์ประกอบ การดำเนินการ BST ทั้งหมดต้องใช้O(depth of node)เวลาและต้องใช้เวลาO(depth of node)เพิ่มเติมในการรักษาข้อมูล "จำนวนองค์ประกอบ" สำหรับการแทรกการลบหรือการหมุนโหนด ดังนั้นการจัดเก็บข้อมูลเกี่ยวกับจำนวนองค์ประกอบในทรีย่อยด้านซ้ายจะคงความซับซ้อนของพื้นที่และเวลาของ BST


59
หากต้องการค้นหารายการที่เล็กที่สุด N คุณจะต้องจัดเก็บขนาดของแผนผังย่อยด้านซ้ายเท่านั้น คุณจะใช้ขนาดของแผนผังย่อยที่ถูกต้องถ้าคุณต้องการที่จะสามารถค้นหารายการที่ใหญ่ที่สุด Nth อันที่จริงคุณสามารถทำให้ราคาถูกลงได้: เก็บขนาดทั้งหมดของต้นไม้ในรากและขนาดของต้นไม้ย่อยด้านซ้าย เมื่อคุณต้องการกำหนดขนาดของแผนผังย่อยด้านขวาคุณสามารถลบขนาดของด้านซ้ายออกจากขนาดทั้งหมดได้
Jerry Coffin

37
BST เสริมดังกล่าวเรียกว่า 'โครงสร้างสถิติคำสั่งซื้อ'
Daniel

10
@Ivlad: ในขั้นตอนที่ 2: ฉันคิดว่า "k - num_elements" ควรเป็น "k - num_elements -1" เนื่องจากคุณต้องรวมองค์ประกอบรากด้วย
understack

1
@understack - ไม่ใช่ถ้าคุณถือว่ารูทเป็นส่วนหนึ่งของทรีย่อย
IVlad

16
หากทรีไม่มีฟิลด์ที่มี "จำนวนองค์ประกอบในทรีย่อยด้านซ้ายและด้านขวา" เมธอดนั้นจะกลายเป็น BigO (n) เนื่องจากคุณจะต้องเดินไปทางขวาหรือซ้ายทรีย่อยที่แต่ละโหนดเพื่อที่จะ คำนวณดัชนี k ของโหนดปัจจุบัน
Robert S.Barnes

68

วิธีแก้ปัญหาที่ง่ายกว่าคือการส่งผ่านตามลำดับและติดตามองค์ประกอบที่จะพิมพ์ในขณะนี้ (โดยไม่ต้องพิมพ์) เมื่อเราไปถึง k ให้พิมพ์องค์ประกอบและข้ามส่วนที่เหลือของการข้ามผ่านต้นไม้

void findK(Node* p, int* k) {
  if(!p || k < 0) return;
  findK(p->left, k);
  --k;
  if(k == 0) { 
    print p->data;
    return;  
  } 
  findK(p->right, k); 
}

1
+1: แนวคิดนี้ไปในทิศทางที่ถูกต้อง แต่บางส่วนที่หลวมอาจจำเป็นต้องขันให้แน่น ดูstackoverflow.com/a/23069077/278326
อรุณ

1
ฉันชอบโซลูชันนี้เนื่องจาก BST ได้รับคำสั่งแล้วการส่งผ่านก็น่าจะเพียงพอแล้ว
Merlin

3
ถ้า n ใกล้เคียงกับจำนวนโหนดทั้งหมดในโครงสร้างนี้อัลกอริทึมของคุณจะใช้เวลา O (n) ในการทำให้เสร็จซึ่งไม่ดีสำหรับคำตอบที่เลือก -O (log n)
Spark8006

13
public int ReturnKthSmallestElement1(int k)
    {
        Node node = Root;

        int count = k;

        int sizeOfLeftSubtree = 0;

        while(node != null)
        {

            sizeOfLeftSubtree = node.SizeOfLeftSubtree();

            if (sizeOfLeftSubtree + 1 == count)
                return node.Value;
            else if (sizeOfLeftSubtree < count)
            {
                node = node.Right;
                count -= sizeOfLeftSubtree+1;
            }
            else
            {
                node = node.Left;
            }
        }

        return -1;
    }

นี่คือการใช้งานของฉันใน C # ตามอัลกอริทึมด้านบนเพียงแค่คิดว่าฉันโพสต์เพื่อให้คนอื่นเข้าใจได้ดีขึ้นว่ามันเหมาะกับฉัน

ขอบคุณ IVlad


11

วิธีแก้ปัญหาที่ง่ายกว่าคือทำการส่งผ่านตามลำดับและติดตามองค์ประกอบที่กำลังจะพิมพ์ด้วยตัวนับ k เมื่อเราถึง k ให้พิมพ์องค์ประกอบ รันไทม์คือ O (n) โปรดจำไว้ว่าประเภทการส่งคืนฟังก์ชันไม่สามารถเป็นโมฆะได้ต้องส่งคืนค่าที่อัปเดตเป็น k หลังจากการเรียกซ้ำแต่ละครั้ง ทางออกที่ดีกว่านี้คือ BST เสริมที่มีค่าตำแหน่งที่เรียงลำดับในแต่ละโหนด

public static int kthSmallest (Node pivot, int k){
    if(pivot == null )
        return k;   
    k = kthSmallest(pivot.left, k);
    k--;
    if(k == 0){
        System.out.println(pivot.value);
    }
    k = kthSmallest(pivot.right, k);
    return k;
}

ฉันเดาว่าโซลูชันของคุณดีกว่าในแง่ของความซับซ้อนของพื้นที่เมื่อเทียบกับ BST เสริม
zach

การค้นหาไม่หยุดแม้ว่าจะพบองค์ประกอบที่เล็กที่สุดลำดับที่ k แล้วก็ตาม
Vineeth Chitteti

10

// เพิ่มเวอร์ชัน java โดยไม่ต้องเรียกซ้ำ

public static <T> void find(TreeNode<T> node, int num){
    Stack<TreeNode<T>> stack = new Stack<TreeNode<T>>();

    TreeNode<T> current = node;
    int tmp = num;

    while(stack.size() > 0 || current!=null){
        if(current!= null){
            stack.add(current);
            current = current.getLeft();
        }else{
            current = stack.pop();
            tmp--;

            if(tmp == 0){
                System.out.println(current.getValue());
                return;
            }

            current = current.getRight();
        }
    }
}

ฉันชอบโซลูชันนี้และโซลูชันแบบวนซ้ำที่เกี่ยวข้อง ตามจริงแล้วคำตอบส่วนใหญ่ของคำถามนี้สับสน / ซับซ้อนเกินกว่าจะอ่านได้
Henley Chiu

ฉันชอบวิธีนี้! ชัดเจนและยิ่งใหญ่!
Rugal

โซลูชันนี้กำลังข้ามต้นไม้ 'ตามลำดับ' และลดตัวนับหลังจากเยี่ยมชมโหนดเพื่อหยุดในภายหลังเมื่อตัวนับมีค่าเท่ากับศูนย์ กรณีที่เลวร้ายที่สุดคือคำสั่ง O (n) ไม่ใช่วิธีที่ดีที่สุดเมื่อเทียบกับโซลูชันแบบวนซ้ำของ @ IVlad ซึ่งกรณีที่เลวร้ายที่สุดใช้เวลา O (log n)
Jorge P.


4

ด้วยโครงสร้างการค้นหาแบบไบนารีธรรมดาสิ่งที่คุณทำได้คือเริ่มจากจุดที่เล็กที่สุดและสำรวจขึ้นไปเพื่อค้นหาโหนดที่ถูกต้อง

หากคุณจะทำสิ่งนี้บ่อยมากคุณสามารถเพิ่มแอตทริบิวต์ให้กับแต่ละโหนดเพื่อระบุจำนวนโหนดที่อยู่ในแผนผังย่อยด้านซ้าย ด้วยวิธีนี้คุณสามารถลงต้นไม้ไปยังโหนดที่ถูกต้องได้โดยตรง


4

เดินตามสั่งซ้ำพร้อมเคาน์เตอร์

Time Complexity: O( N ), N is the number of nodes
Space Complexity: O( 1 ), excluding the function call stack

แนวคิดนี้คล้ายกับโซลูชันของ @prasadvk แต่มีข้อบกพร่องบางประการ (ดูหมายเหตุด้านล่าง) ดังนั้นฉันจึงโพสต์สิ่งนี้เป็นคำตอบแยกต่างหาก

// Private Helper Macro
#define testAndReturn( k, counter, result )                         \
    do { if( (counter == k) && (result == -1) ) {                   \
        result = pn->key_;                                          \
        return;                                                     \
    } } while( 0 )

// Private Helper Function
static void findKthSmallest(
    BstNode const * pn, int const k, int & counter, int & result ) {

    if( ! pn ) return;

    findKthSmallest( pn->left_, k, counter, result );
    testAndReturn( k, counter, result );

    counter += 1;
    testAndReturn( k, counter, result );

    findKthSmallest( pn->right_, k, counter, result );
    testAndReturn( k, counter, result );
}

// Public API function
void findKthSmallest( Bst const * pt, int const k ) {
    int counter = 0;
    int result = -1;        // -1 := not found
    findKthSmallest( pt->root_, k, counter, result );
    printf("%d-th element: element = %d\n", k, result );
}

หมายเหตุ (และความแตกต่างจากโซลูชันของ @ prasadvk):

  1. if( counter == k )จำเป็นต้องมีการทดสอบในสามตำแหน่ง: (a) หลังทรีย่อยด้านซ้าย (b) หลังรูทและ (c) หลังทรีย่อยด้านขวา เพื่อให้แน่ใจว่าองค์ประกอบ kth ถูกตรวจพบสำหรับทุกสถานที่กล่าวคือโดยไม่คำนึงถึงทรีย่อยที่อยู่

  2. if( result == -1 )จำเป็นต้องทำการทดสอบเพื่อให้แน่ใจว่ามีการพิมพ์องค์ประกอบผลลัพธ์เท่านั้นมิฉะนั้นองค์ประกอบทั้งหมดที่เริ่มจาก kth ที่เล็กที่สุดจนถึงรูทจะถูกพิมพ์


ความซับซ้อนของเวลาสำหรับการแก้ปัญหานี้คือการO(k + d)ที่dความลึกสูงสุดของต้นไม้ ดังนั้นจึงใช้ตัวแปร global counterแต่คำถามนี้ผิดกฎหมาย
Valentin Shergin

สวัสดีอรุณคุณช่วยอธิบายด้วยตัวอย่างได้ไหม ฉันไม่เข้าใจสิ่งนี้โดยเฉพาะจุดแรกของคุณ
Andy897

3

สำหรับต้นไม้ค้นหาที่ไม่สมดุลต้องใช้ O (n)

สำหรับโครงสร้างการค้นหาที่สมดุลจะใช้O (k + log n)ในกรณีที่เลวร้ายที่สุด แต่เพียงแค่O (k)ในAmortizedความหมาย

การมีและการจัดการจำนวนเต็มพิเศษสำหรับทุกโหนด: ขนาดของแผนผังย่อยจะให้O (log n)ความซับซ้อนของเวลาต้นไม้ค้นหาที่สมดุลดังกล่าวมักเรียกว่า RankTree

โดยทั่วไปมีวิธีแก้ไข (ไม่อิงตามต้นไม้)

ความนับถือ.


1

สิ่งนี้ใช้ได้ดี: status: คืออาร์เรย์ที่เก็บไว้ว่าจะพบองค์ประกอบหรือไม่ k: เป็นองค์ประกอบ kth ที่จะพบ count: ติดตามจำนวนโหนดที่ข้ามระหว่างการข้ามผ่านต้นไม้

int kth(struct tree* node, int* status, int k, int count)
{
    if (!node) return count;
    count = kth(node->lft, status, k, count);  
    if( status[1] ) return status[0];
    if (count == k) { 
        status[0] = node->val;
        status[1] = 1;
        return status[0];
    }
    count = kth(node->rgt, status, k, count+1);
    if( status[1] ) return status[0];
    return count;
}

1

แม้ว่านี่จะไม่ใช่วิธีแก้ปัญหาที่ดีที่สุด แต่ก็เป็นอีกวิธีหนึ่งที่เป็นไปได้ซึ่งฉันคิดว่าบางคนอาจคิดว่าน่าสนใจ:

/**
 * Treat the bst as a sorted list in descending order and find the element 
 * in position k.
 *
 * Time complexity BigO ( n^2 )
 *
 * 2n + sum( 1 * n/2 + 2 * n/4 + ... ( 2^n-1) * n/n ) = 
 * 2n + sigma a=1 to n ( (2^(a-1)) * n / 2^a ) = 2n + n(n-1)/4
 *
 * @param t The root of the binary search tree.
 * @param k The position of the element to find.
 * @return The value of the element at position k.
 */
public static int kElement2( Node t, int k ) {
    int treeSize = sizeOfTree( t );

    return kElement2( t, k, treeSize, 0 ).intValue();
}

/**
 * Find the value at position k in the bst by doing an in-order traversal 
 * of the tree and mapping the ascending order index to the descending order 
 * index.
 *
 *
 * @param t Root of the bst to search in.
 * @param k Index of the element being searched for.
 * @param treeSize Size of the entire bst.
 * @param count The number of node already visited.
 * @return Either the value of the kth node, or Double.POSITIVE_INFINITY if 
 *         not found in this sub-tree.
 */
private static Double kElement2( Node t, int k, int treeSize, int count ) {
    // Double.POSITIVE_INFINITY is a marker value indicating that the kth 
    // element wasn't found in this sub-tree.
    if ( t == null )
        return Double.POSITIVE_INFINITY;

    Double kea = kElement2( t.getLeftSon(), k, treeSize, count );

    if ( kea != Double.POSITIVE_INFINITY )
        return kea;

    // The index of the current node.
    count += 1 + sizeOfTree( t.getLeftSon() );

    // Given any index from the ascending in order traversal of the bst, 
    // treeSize + 1 - index gives the
    // corresponding index in the descending order list.
    if ( ( treeSize + 1 - count ) == k )
        return (double)t.getNumber();

    return kElement2( t.getRightSon(), k, treeSize, count );
}

1

ลายเซ็น:

Node * find(Node* tree, int *n, int k);

เรียกว่า:

*n = 0;
kthNode = find(root, n, k);

ความหมาย:

Node * find ( Node * tree, int *n, int k)
{
   Node *temp = NULL;

   if (tree->left && *n<k)
      temp = find(tree->left, n, k);

   *n++;

   if(*n==k)
      temp = root;

   if (tree->right && *n<k)
      temp = find(tree->right, n, k);

   return temp;
}

1

นี่คือ 2 เซ็นต์ของฉัน ...

int numBSTnodes(const Node* pNode){
     if(pNode == NULL) return 0;
     return (numBSTnodes(pNode->left)+numBSTnodes(pNode->right)+1);
}


//This function will find Kth smallest element
Node* findKthSmallestBSTelement(Node* root, int k){
     Node* pTrav = root;
     while(k > 0){
         int numNodes = numBSTnodes(pTrav->left);
         if(numNodes >= k){
              pTrav = pTrav->left;
         }
         else{
              //subtract left tree nodes and root count from 'k'
              k -= (numBSTnodes(pTrav->left) + 1);
              if(k == 0) return pTrav;
              pTrav = pTrav->right;
        }

        return NULL;
 }

0

นี่คือสิ่งที่ฉันคิดและมันได้ผล มันจะทำงานใน o (log n)

public static int FindkThSmallestElemet(Node root, int k)
    {
        int count = 0;
        Node current = root;

        while (current != null)
        {
            count++;
            current = current.left;
        }
        current = root;

        while (current != null)
        {
            if (count == k)
                return current.data;
            else
            {
                current = current.left;
                count--;
            }
        }

        return -1;


    } // end of function FindkThSmallestElemet

3
ฉันไม่คิดว่าวิธีนี้จะใช้ได้ผล จะเกิดอะไรขึ้นถ้า Kth ที่เล็กที่สุดอยู่ในทรีย่อยด้านขวาของโหนดทรี
Anil Vishnoi

0

เราสามารถใช้การส่งผ่านตามลำดับและผลักองค์ประกอบที่เยี่ยมชมไปยังสแต็กได้ ป๊อป k จำนวนครั้งเพื่อรับคำตอบ

เรายังสามารถหยุดหลังจากองค์ประกอบ k


1
นี่ไม่ใช่ทางออกที่ดีที่สุด
bragboy

0

โซลูชันสำหรับกรณี BST ที่สมบูรณ์: -

Node kSmallest(Node root, int k) {
  int i = root.size(); // 2^height - 1, single node is height = 1;
  Node result = root;
  while (i - 1 > k) {
    i = (i-1)/2;  // size of left subtree
    if (k < i) {
      result = result.left;
    } else {
      result = result.right;
      k -= i;
    }  
  }
  return i-1==k ? result: null;
}

0

เคอร์เนลลินุกซ์มีโครงสร้างข้อมูลต้นไม้สีแดงดำที่ยอดเยี่ยมซึ่งรองรับการดำเนินการตามอันดับใน O (log n) ใน linux / lib / rbtree.c

พอร์ต Java น้ำมันดิบมากนอกจากนี้ยังสามารถพบได้ที่http://code.google.com/p/refolding/source/browse/trunk/core/src/main/java/it/unibo/refolding/alg/RbTree.java , ร่วมกับ RbRoot.java และ RbNode.java องค์ประกอบที่ n สามารถรับได้โดยการเรียก RbNode.nth (โหนด RbNode, int n) ผ่านรากของต้นไม้


0

นี่คือเวอร์ชันที่กระชับในC #ที่ส่งคืนองค์ประกอบที่เล็กที่สุด k-th แต่ต้องมีการส่ง k in เป็นอาร์กิวเมนต์อ้างอิง (เป็นวิธีเดียวกับ @prasadvk):

Node FindSmall(Node root, ref int k)
{
    if (root == null || k < 1)
        return null;

    Node node = FindSmall(root.LeftChild, ref k);
    if (node != null)
        return node;

    if (--k == 0)
        return node ?? root;
    return FindSmall(root.RightChild, ref k);
}

มัน O (log n) เพื่อหาโหนดที่เล็กที่สุดแล้ว O (k) เพื่อสำรวจ K-TH โหนดจึงเป็น O (k + log n)


แล้วเวอร์ชั่น java ล่ะ?
Henley Chiu


0

ฉันไม่พบอัลกอริทึมที่ดีกว่า.. จึงตัดสินใจเขียนขึ้นมา :) แก้ไขฉันถ้าสิ่งนี้ผิด

class KthLargestBST{
protected static int findKthSmallest(BSTNode root,int k){//user calls this function
    int [] result=findKthSmallest(root,k,0);//I call another function inside
    return result[1];
}
private static int[] findKthSmallest(BSTNode root,int k,int count){//returns result[]2 array containing count in rval[0] and desired element in rval[1] position.
    if(root==null){
        int[]  i=new int[2];
        i[0]=-1;
        i[1]=-1;
        return i;
    }else{
        int rval[]=new int[2];
        int temp[]=new int[2];
        rval=findKthSmallest(root.leftChild,k,count);
        if(rval[0]!=-1){
            count=rval[0];
        }
        count++;
        if(count==k){
            rval[1]=root.data;
        }
        temp=findKthSmallest(root.rightChild,k,(count));
        if(temp[0]!=-1){
            count=temp[0];
        }
        if(temp[1]!=-1){
            rval[1]=temp[1];
        }
        rval[0]=count;
        return rval;
    }
}
public static void main(String args[]){
    BinarySearchTree bst=new BinarySearchTree();
    bst.insert(6);
    bst.insert(8);
    bst.insert(7);
    bst.insert(4);
    bst.insert(3);
    bst.insert(4);
    bst.insert(1);
    bst.insert(12);
    bst.insert(18);
    bst.insert(15);
    bst.insert(16);
    bst.inOrderTraversal();
    System.out.println();
    System.out.println(findKthSmallest(bst.root,11));
}

}


0

นี่คือรหัส java

สูงสุด (Node root, int k) - เพื่อค้นหา kth ที่ใหญ่ที่สุด

min (Node root, int k) - เพื่อหา kth ที่เล็กที่สุด

static int count(Node root){
    if(root == null)
        return 0;
    else
        return count(root.left) + count(root.right) +1;
}
static int max(Node root, int k) {
    if(root == null)
        return -1;
    int right= count(root.right);

    if(k == right+1)
        return root.data;
    else if(right < k)
        return max(root.left, k-right-1);
    else return max(root.right, k);
}

static int min(Node root, int k) {
    if (root==null)
        return -1;

    int left= count(root.left);
    if(k == left+1)
        return root.data;
    else if (left < k)
        return min(root.right, k-left-1);
    else
        return min(root.left, k);
}

0

มันก็ใช้ได้เช่นกัน เพียงแค่เรียกใช้ฟังก์ชันด้วย maxNode ในแผนภูมิ

def k_largest (self, node, k): if k <0: return None
if k == 0: return node else: k - = 1 return self.k_largest (self.pred Prioror (node), k)


0

ฉันคิดว่านี่ดีกว่าคำตอบที่ยอมรับเพราะไม่จำเป็นต้องแก้ไขโหนดต้นไม้ดั้งเดิมเพื่อเก็บจำนวนโหนดลูกของมัน

เราจำเป็นต้องใช้การส่งผ่านตามลำดับเพื่อนับโหนดที่เล็กที่สุดจากซ้ายไปขวาหยุดค้นหาเมื่อจำนวนเท่ากับ K

private static int count = 0;
public static void printKthSmallestNode(Node node, int k){
    if(node == null){
        return;
    }

    if( node.getLeftNode() != null ){
        printKthSmallestNode(node.getLeftNode(), k);
    }

    count ++ ;
    if(count <= k )
        System.out.println(node.getValue() + ", count=" + count + ", k=" + k);

    if(count < k  && node.getRightNode() != null)
        printKthSmallestNode(node.getRightNode(), k);
}

0

แนวทางที่ดีที่สุดมีอยู่แล้ว แต่ฉันต้องการเพิ่มรหัสง่ายๆสำหรับสิ่งนั้น

int kthsmallest(treenode *q,int k){
int n = size(q->left) + 1;
if(n==k){
    return q->val;
}
if(n > k){
    return kthsmallest(q->left,k);
}
if(n < k){
    return kthsmallest(q->right,k - n);
}

}

int size(treenode *q){
if(q==NULL){
    return 0;
}
else{
    return ( size(q->left) + size(q->right) + 1 );
}}

0

การใช้คลาสผลลัพธ์เสริมเพื่อติดตามว่าพบโหนดหรือไม่และปัจจุบัน k.

public class KthSmallestElementWithAux {

public int kthsmallest(TreeNode a, int k) {
    TreeNode ans = kthsmallestRec(a, k).node;
    if (ans != null) {
        return ans.val;
    } else {
        return -1;
    }
}

private Result kthsmallestRec(TreeNode a, int k) {
    //Leaf node, do nothing and return
    if (a == null) {
        return new Result(k, null);
    }

    //Search left first
    Result leftSearch = kthsmallestRec(a.left, k);

    //We are done, no need to check right.
    if (leftSearch.node != null) {
        return leftSearch;
    }

    //Consider number of nodes found to the left
    k = leftSearch.k;

    //Check if current root is the solution before going right
    k--;
    if (k == 0) {
        return new Result(k - 1, a);
    }

    //Check right
    Result rightBalanced = kthsmallestRec(a.right, k);

    //Consider all nodes found to the right
    k = rightBalanced.k;

    if (rightBalanced.node != null) {
        return rightBalanced;
    }

    //No node found, recursion will continue at the higher level
    return new Result(k, null);

}

private class Result {
    private final int k;
    private final TreeNode node;

    Result(int max, TreeNode node) {
        this.k = max;
        this.node = node;
    }
}
}

0

Python Solution Time Complexity: O (n) Space Complexity: O (1)

แนวคิดคือการใช้Morris Inorder Traversal

class Solution(object):
def inorderTraversal(self, current , k ):
    while(current is not None):    #This Means we have reached Right Most Node i.e end of LDR traversal

        if(current.left is not None):  #If Left Exists traverse Left First
            pre = current.left   #Goal is to find the node which will be just before the current node i.e predecessor of current node, let's say current is D in LDR goal is to find L here
            while(pre.right is not None and pre.right != current ): #Find predecesor here
                pre = pre.right
            if(pre.right is None):  #In this case predecessor is found , now link this predecessor to current so that there is a path and current is not lost
                pre.right = current
                current = current.left
            else:                   #This means we have traverse all nodes left to current so in LDR traversal of L is done
                k -= 1
                if(k == 0):
                    return current.val
                pre.right = None       #Remove the link tree restored to original here 
                current = current.right
        else:               #In LDR  LD traversal is done move to R 
            k -= 1
            if(k == 0):
                return current.val
            current = current.right

    return 0

def kthSmallest(self, root, k):
    return self.inorderTraversal( root , k  )

-1

ฉันเขียนฟังก์ชันเรียบร้อยเพื่อคำนวณองค์ประกอบที่เล็กที่สุด kth ฉันใช้การส่งผ่านตามลำดับและหยุดเมื่อถึงองค์ประกอบที่เล็กที่สุด kth

void btree::kthSmallest(node* temp, int& k){
if( temp!= NULL)   {
 kthSmallest(temp->left,k);       
 if(k >0)
 {
     if(k==1)
    {
      cout<<temp->value<<endl;
      return;
    }

    k--;
 }

 kthSmallest(temp->right,k);  }}

ไม่มีการระบุเมตริกว่าเหตุใดจึงเหมาะสมที่สุด ทั้งกรณีใหญ่และเล็ก
Woot4Moo

-1
int RecPrintKSmallest(Node_ptr head,int k){
  if(head!=NULL){
    k=RecPrintKSmallest(head->left,k);
    if(k>0){
      printf("%c ",head->Node_key.key);
      k--;
    }
    k=RecPrintKSmallest(head->right,k);
  }
  return k;
}

2
โปรดแนบรหัสที่มีคำอธิบายในระดับหนึ่งเสมอว่ามันทำงานอย่างไรและจะช่วยแก้ปัญหาได้อย่างไร
Ren

-1
public TreeNode findKthElement(TreeNode root, int k){
    if((k==numberElement(root.left)+1)){
        return root;
    }
    else if(k>numberElement(root.left)+1){
        findKthElement(root.right,k-numberElement(root.left)-1);
    }
    else{
        findKthElement(root.left, k);
    }
}

public int numberElement(TreeNode node){
    if(node==null){
        return 0;
    }
    else{
        return numberElement(node.left) + numberElement(node.right) + 1;
    }
}

-1
public static Node kth(Node n, int k){
    Stack<Node> s=new Stack<Node>();
    int countPopped=0;
    while(!s.isEmpty()||n!=null){
      if(n!=null){
        s.push(n);
        n=n.left;
      }else{
        node=s.pop();
        countPopped++;
        if(countPopped==k){
            return node;
        }
        node=node.right;

      }
  }

}

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.