LeetCode[230] Kth Smallest Element In a BST 解法及代码

题目描述

Given a binary search tree, write a function kthSmallest to find the kth smallest element in it.

Note:
You may assume k is always valid, 1 ≤ k ≤ BST’s total elements.

Example 1:

Input: root = [3,1,4,null,2], k = 1
3
/ \
1 4
\
  2
Output: 1
Example 2:

Input: root = [5,3,6,2,4,null,null,1], k = 3
5
/ \
3 6
/ \
2 4
/
1
Output: 3
Follow up:
What if the BST is modified (insert/delete operations) often and you need to find the kth smallest frequently? How would you optimize the kthSmallest routine?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-smallest-element-in-a-bst
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

找出BST(二叉查找树)第K小的元素

解法

BST 也就是满足 左子树 < 根 < 右子树 条件的二叉树。因此,我们用中序遍历即可以得到从小到大排列的元素数组,题目要求返回第K小的元素,即我们只要遍历到第K个元素即可。 用常规的递归遍历代码实现快,但是程序运行速度较慢(中国版leetcode 10%),用迭代法遍历代码实现有难度,比较考验代码功底,但程序运行速度快(中国版Leetcode 70%)。

代码

 // 递归
 void traversalInorder(TreeNode* root, vector& result, int k) {
     if (result.size() == k || root == NULL) {
         return;
     }
     traversalInorder(root->left, result, k);
     result.emplace_back(root->val);
     traversalInorder(root->right, result, k);
 }

 // 迭代
void traversalInorder(TreeNode* root, vector& result, int k) {
    stack stack_;
    auto node = root;
    while(node || !stack_.empty()) {
        while(node) {
            if (node->left) {
                stack_.push(node);
                node = node->left;
            } else {
                result.emplace_back(node->val);
                if (result.size() == k)
                    return;
                node = node->right;
            }
        }
        if (!stack_.empty()) {
            node = stack_.top();
            stack_.pop();
            result.emplace_back(node->val);
            if (result.size() == k)
                return;
            node = node->right;
        }
    }
}

int kthSmallest(TreeNode* root, int k) {
    vector result;
    traversalInorder(root, result, k);
    return result[k-1];    
}

LeetCode[148]Sort List 解法及代码

题目描述:

Sort a linked list in O(n log n) time using constant space complexity.

Example 1:

Input: 4->2->1->3
Output: 1->2->3->4
Example 2:

Input: -1->5->3->4->0
Output: -1->0->3->4->5

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/sort-list
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解法

题目要求算法复杂度是O(nlogn),故不能使用冒泡和插入排序,因为是链表不能随机寻址,所以只能使用归并排序。

链表有两个基本操作需要先实现,拆分(split)和合并(merge), 用这两个基本操作就可实现算法。

拆分(split): 给一个head和n, 拆成n个元素的左链表,剩下为右链表,返回右链表
如:1->2->3, 1; 返回2->3;

合并(merge): 给两个链表,按从小到大的顺序合并成一个链表,并返回
如:1->3, 2->4; 1->2->3->4;

则题目所给4->2->1->3, 先拆成4,2,1,3, 然后归并2->4, 1->3, 1->2->3->4

因为题目又要求只能用常量空间,所以不能开额外的容器存拆出来的元素,对编码技巧有一定要求。

代码

  ListNode* merge(ListNode* l1, ListNode* l2) {
    ListNode dummyHead(0);
    ListNode* p = &dummyHead;
    while (l1 && l2) {
      if (l1->val < l2->val) {
        p->next = l1;
        l1 = l1->next;
      } else {
        p->next = l2;
        l2 = l2->next;
      }
      p = p->next;
    }
    p->next = l1 ? l1 : l2;

    return dummyHead.next;
  }

  ListNode* split(ListNode* head, int n) {
    ListNode dummyNode(0);
    auto p = &dummyNode;
    int len = 0;
    auto pre = head;
    while(head && len <= n) {
      if (len == n) { p->next = head;
        pre->next = NULL;
        break;
      }
      pre = head;
      head = head->next;
      len++;
    }
    return dummyNode.next;
  }

  ListNode* sortList(ListNode* head) {
    int len = 0;
    ListNode* p = head;
    while(p) {
      p = p->next;
      len++;
    }

    ListNode dummyHead(0);
    dummyHead.next = head;
    for(int size = 1; size <= len; size <<= 1) {
      auto cur = dummyHead.next;
      auto tail = &dummyHead;
      while (cur) {
        auto left = cur;
        auto right = split(left, size);
        cur = split(right, size);
        tail->next = merge(left, right);
        while(tail->next) tail = tail->next;
      }
    }
    return dummyHead.next;
  }

2020年,真是一个异常艰苦的年份

在大年初二,全国人民都还待在家里,为避免疫情的进一步扩散尽自己一份力量的时候,80,90后的精神偶像,刚在年三十录制了视频祝中国人民新春快乐的科比,在北京时间凌晨4点左右因直升机意外坠毁去世了。这是一个很没有实感的消息,但它却是真实的,很残酷。你永远不知道明天和意外哪个会先到来,科比甚至还没能活着见证自己进入NBA名人堂,珍惜当下!
科比走了,曼巴精神永存!

leetcode[215] Kth Largest Element in an Array 解法及代码

题目描述:

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

示例 1:

输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:

输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
说明:

你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

解法1:

最偷懒的解法,直接用stl的部分排序(全排序必然超时), 输出第K个元素


#include <algorithm>

int findKthLargest(vector<int>& nums, int k) {
    std::partial_sort(nums.begin(), nums.begin() + k, nums.end(), [](auto& a, auto& b) {
        return a > b;
    });
    return nums[k - 1];
}

这里需要注意的是partial_sort的第三个参数,需要自定义排序规则,默认从小到大,我们需要从大到小。

解法2:

建立一个大顶堆,使用堆排序,排到第K个数时停止并返回,代码:


void percolateDown(vector<int>& nums, int start, int end) {
    for (int j = 2 * start + 1; j <= end; j = 2 * start + 1) {
        if (j < end && nums[j + 1] >= nums[j]) j++;
        if (nums[start] > nums[j]) break;
        int temp = nums[start];
        nums[start] = nums[j];
        nums[j] = temp;
        start = j;
    }
}

void makeHeap(vector<int>& nums) {
    int len = nums.size();
    for (int r = len / 2 - 1; r >= 0; r--) {
        percolateDown(nums, r, len - 1);
    }
}

int heapSort(vector<int>& nums, int k) {
    int n = nums.size() - 1;
    for (int i = 0; i < k; i++) {
        int temp = nums[n];
        nums[n] = nums[0];
        nums[0] = temp;
        n--;
        percolateDown(nums, 0, n);
    }
    return nums[nums.size() - k];
}

int findKthLargest(vector<int>& nums, int k) {
    makeHeap(nums);
    return heapSort(nums, k);
}