用于查找获取排序列表所需的最小移动元素到结束步骤的算法

时间:2017-10-21 14:36:58

标签: c++ algorithm

我们给出了一个未排序的int数组(不要假设数组只包含正整数且没有重复的元素。)。每次,我们只允许选择一个随机元素并将其放在数组的末尾。将此数组作为排序列表(按升序排列)所需的最小步骤是什么?

您可以理解

的示例

假设给定列表为{2,1,4,3},则所需的最小步骤为3.

步骤1:选择2,将其放在数组的末尾,现在数组为{1,4,3,2}

第2步:选择3,将其放在数组的末尾,现在数组为{1,4,2,3}

步骤3:选择4,将其放在数组的末尾,现在数组为{1,2,3,4}

我试图自己解决这个问题。但我不确定我的解决方案是否具有最小的时间复杂度和空间复杂性。

我的解决方案

假设给定的数组是nums,它是int的向量。我的解决方案是(现在有完整的代码可以自己运行)

#include <vector>
#include <iostream>

using namespace std;

int main(){

    int N; // N is the number of elements in this array
    cin >> N;
    vector<int> nums(N);
    vector<int> nums_copy(N);
    for (int i = 0; i != N; ++i){
        cin >> nums[i];
        nums_copy[i] = nums[i];
    }
    sort(nums_copy.begin(), nums_copy.end());

    size_t j = 0;
    for (size_t i = 0, end = nums.size(); i != end; ++i){
        if (nums[i] == nums_copy[j])
            ++j;
    }

    cout << nums.size() - j << endl;
    return 0;
}

我们的想法是对原始数组进行排序,然后计算原始数组中元素的数量,这些元素在排序数组中的顺序正确(上面代码中为j)。因此,所需的最低步骤仅为nums.size()-j

空间复杂度为O(n),时间复杂度为O(nlog(n)) 排序数组的时间复杂度。

如果您认为我的解决方案有问题或者您在时间或空间复杂性方面都有更好的解决方案,请分享您的解决方案。

2 个答案:

答案 0 :(得分:2)

我的代码只需要O(1)空间和O(n)时间:

#include <iostream>
#include <vector>
#include <climits>

static std::size_t xsteps(const std::vector<int> &nums) {
    int min = nums.end()[-1], bad_min = INT_MAX;
    for (std::size_t i = nums.size(); i--; ) {
        if (nums[i] < min) {
            min = nums[i];
        } else if (min < nums[i] && nums[i] < bad_min) {
            bad_min = nums[i];
        }
    }

    std::size_t count = 0;
    std::size_t i;
    for (i = 0; i < nums.size(); i++) {
        if (nums[i] >= bad_min) {
            count++;
        }
    }
    while (i-- && nums[i] >= bad_min) {
        if (nums[i] == bad_min) {
            count--;
        }
    }

    return count;
}

int main() {
    std::cout << xsteps({2, 1, 4, 3}) << '\n';
}

这个想法是首先找到不合适的最小元素(即在其右边有一个较小的元素)。这是由第一个循环完成的,它从末尾开始迭代,跟踪到目前为止看到的最小元素(min)和不合适的最小元素(bad_min)。

在此循环结束时,我们知道所有小于bad_min的元素已经在正确的位置,我们不需要触摸它们。

然后我们再次迭代向量。我们将所有大于或等于bad_min的元素都计为不合适。然而,这高估了真实的数量:bad_min的所有副本本身不合适(即不跟随较小的元素)不需要移动。

这在第三个循环中得到修复。它从右边迭代并递减计数器,找到每个bad_min,并在它看到一个较小的元素时立即停止。

答案 1 :(得分:-1)

#include <iostream>
#include <string>
#include <vector>

using namespace std;

int calcsort(vector<int>& nums)
{
    int start=1;
    for(int i=0;i<nums.size();i++)
    {
        if (nums[i]==start)
            start++;
    }
    return (nums.size()-(start-1));
}
int main()
{
    vector<int> nums={2,1,4,3};
    cout<<calcsort(nums)<<endl;
}

这个想法是找到最大的升序顺序。显然,最小步数= nums.size() - subsequenсe的长度。就这样。