例如
8314925去掉4個數,留下125最小,注意有前后順序要求,要是沒有順序當然是123。
解決方案
貪心算法,在每次被訪問的位置保證有最優解。
思路一
分析:求一共n位,求其中的m位組成的數最小。那么這個m位的數,最高位應該在原數的最高位到第m位區間找,要不然就不能當第m位了,如下圖(得到3位數最小,要是百位數在25中找,就當不了百位數了):
同樣找十位數時只能在百味數到目前位置中間搜,整個過程圖示如下:
注意
在區間有多個最小值,取距離最大的,保證下一位數有足夠大的查找空間。
參考代碼
#include <iostream> #include <cstdlib> #include <cassert> using namespace std; int *q; int findMinIndex(int arr[], int beg, int end) //[] { if(beg > end) return -1; int minv = arr[beg]; int minIndex = beg; for(int i = beg + 1; i <= end; ++i) { if(arr[i] < minv) { minv = arr[i]; minIndex = i; } } return minIndex; } int getRemain(int arr[], int size, int k) { assert(size > k && k >= 0); int rev = 0, revIndex = -1; for(int i = size - k; i < size; ++i) { revIndex = findMinIndex(arr, revIndex + 1, i); rev = rev * 10 + arr[revIndex]; } return rev; } int main() { int arr[] = {3, 1, 6, 4, 8, 5, 7}; size_t size = sizeof(arr) / sizeof(int); int remainNum; for (int k = size-1; k > 0; --k) { int remainNum = getRemain(arr, size, size - k); cout << "When k = " << k << ", the remaining value is:" << remainNum << endl; } }
結果
分析
時間復雜度O(KN)
思路二
分析:從前往后找,每次訪問一位,比較該位前邊的數,如果比該位大,果斷干掉,例如:
同樣以此往后遍歷,知道干掉個數為k或訪問到最后了,整個過程圖示如下圖。當然遍歷到最后還沒有干掉K個元素,說明剩下的已經為升序了,這樣就在留下的數中取出前(n-k)個,整合成整數就是最小值。
參考代碼
#include <iostream> #include <cassert> using namespace std; int getRemain(int *arr, int size, int k) { assert(size > k && k > 0); int tmp = size - k; int cur = 0, pre; int rev = 0; while(k != 0 && cur < size) { pre = cur - 1; while(pre >= 0) { if(arr[pre] >= arr[cur]) { for(int i = pre; i < size; ++i) arr[i] = arr[i+1]; --cur; --k; --size; } --pre; } ++cur; } for(int i = 0; i < tmp; ++i) { rev = rev * 10 + arr[i]; } return rev; } int main() { int arr[] = {3, 1, 6, 4, 8, 5, 7}; size_t size = sizeof(arr) / sizeof(int); int remainNum; remainNum = getRemain(arr, size, 3); cout << "When k = " << 3 << ", the remaining value is:" << remainNum << endl; }
分析
時間復雜度O(KN)