比较简单粗暴的解法,先将input数组排序,然后直接返回排序后数组的前k位。关于时间复杂度,由于这里用的是冒泡排序所以时间复杂度为O(n^2+k),n为input长度。而若使用时间复杂度更低的排序方法,如快速排序,则可以达到O(nlogn+k)。此处空间复杂度则小于题目要求,仅为O(k)。

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {  
        vector<int> result;
        if(input.size() == 0){
            return result;
        }
        for(int i = 0;i < input.size()-1;i++){
            for(int j = 0;j < input.size()-1-i;j++){
                if(input.at(j)>input.at(j+1)){
                    int tmp = input.at(j);
                    input.at(j) = input.at(j+1);
                    input.at(j+1) = tmp;
                }
            }
        }
        for(int i = 0;i < k;i++){
            result.push_back(input.at(i));
        }
        return result;
    }
};



最近刚做了一道归并排序的题,为了加深理解,所以回来用归并排序重新写一遍这个题,换汤不换药,核心思路还是对原数组排序后取前k个数。

class Solution {
public:
    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
        vector<int> temp(input.size());
        vector<int> result;
        if(!input.size() || !k){
            return result;
        }
        merge(input, temp, 0, input.size() - 1);
        for(int i = 0;i < k;i++){
            result.push_back(input.at(i));
        }
        return result;
    }
    void merge(vector<int>& input, vector<int>& temp,int left, int right){
        if(left >= right){
            return;
        }
        int mid = left + (right - left)/2;
        merge(input, temp, left, mid);
        merge(input, temp, mid + 1, right);
        for(int i = left;i <= right;i++){
            temp.at(i) = input.at(i);
        }
        int l = left;
        int r = mid + 1;
        for(int i = left;i <= right;i++){
            if(l == mid + 1){
                input.at(i) = temp.at(r++);
            }
            else if(r == right + 1 || temp.at(l) < temp.at(r)){
                input.at(i) = temp.at(l++);
            }
            else{
                input.at(i) = temp.at(r++);
            }
        }
    }
};



写的时候遇到一个小坑。

if(l == mid + 1){
  first sentence...
}
else if(r == right + 1 || temp.at(l) < temp.at(r)){
  secound sentence...
}
else{
  first sentence...
}
----------------------------------------------------
if(r == right + 1 || temp.at(l) < temp.at(r)){
  first sentence...
}
else{
  secound sentence...
}

在核心交换逻辑中有以上的判断代码,原版是上面的判断逻辑。我在写的时候想,上下两个语句中执行的代码都一样,中间夹了个if else,那直接把这两个执行体一样的判断合在一起做一个else不就行了。
事实证明这样做是不行的,尽管他们执行体一样,但判断逻辑的先后对程序有很大影响。下面哪种写法,只要当左数组数比右数组数小就会直接移动左指针,而并不判断左指针是否越界,所以必须在移动左指针前执行越界判断逻辑。同理,之所以在第二个判断体判断右指针是否越界,是因为第三个判断题要移动右指针。

在对模版代码的逻辑进行优化时,一定要在深思熟虑后在行动,以免因自以为是造成错误。