(笔试题)删除K位数字

题目:

现有一个 n 位数,你需要删除其中的 k 位,请问如何删除才能使得剩下的数最大?

比如当数为 2319274, k=1 时,删去 2 变成 319274 后是可能的最大值。

思路:

1、贪心算法

每次从高位向低位数,删除高位数字比低位数字小的那位数字。如2319274

第一次2<3,删除2,得到319274

第二次3>1,略过,1<9,删除1,得到39274

第三次3<9,删除3,得到9274

。。。。。。

// greedy method
string deleteKBits_1(string str,int k){
    int tlen=str.length();
    bool flag=true;
    int len;
    while(k && flag){
        len=str.length();
        for(int i=0;i<len-1;i++){
            if(str[i]<str[i+1]){
                str.erase(i,1);
                flag=true;
                break;
            }
        }
        k--;
    }
    return str.substr(0,tlen-k);
}

2、动态规划

分析:

假设str为长度为n的数字字符串,S[i][j]表示删除str[0...i-1]中j个数字后的最大字符数字。

如果删除第i个数,则S[i][j]等于删除前i-1个字符中的j-1位的最优解,即S[i][j]=S[i-1][j-1];

如果不删除第i个数,则S[i][j]等于删除前i-1个字符中j位的最优解+str[i],即S[i][j]=S[i-1][j]+str[i-1];

即S[i][j]=max(S[i-1][j-1],S[i-1][j]+str[i-1])

初始状态为当j=0时,不删除任何位的数字,即S[i][j]=str[0...i-1];

状态转移方程如下:

S[i][j]=

strsub(0,i); (if j==0)

max(S[i-1][j-1],S[i-1][j]+str[i-1]); (if 0<j<i;0<j<=k)

时间复杂度:O(n*k)

空间复杂度:O(n*k)

优化:

从上述的转移方程S[i][j]=max(S[i-1][j-1],S[i-1][j]+str[i-1]),可以看出在每一次i循环中,只与i-1相关,因此不需要用单独使用一个维度的数组来存储,只需要每次通过一个变量last保存上一次的结果。因此转移方程可以简化为S[j]=max(last,S[j]+str[i-1])

时间复杂度:O(n*k)

空间复杂度:O(k)

// dynamic programming
// time complexity: O(n*k)
// space complexity: O(n*k)
string deleteKBits_2(string str,int k){
    int tlen=str.length();
    vector<vector<string> > nums(tlen+1,vector<string>(k+1));
    string s1,s2;
    for(int i=1;i<=tlen;i++){
        for(int j=0;j<i && j<=k;j++){
            if(j==0){
                nums[i][j]=str.substr(0,i);
            }
            else{
                s1=nums[i-1][j-1];
                s2=nums[i-1][j]+str[i-1];
                if(s1.compare(s2)<=0)
                    nums[i][j]=s2;
                else
                    nums[i][j]=s1;
            }
        }
    }
    return nums[tlen][k];
}

// dynamic programming
// time complexity: O(n*k)
// space complexity: O(k)
string deleteKBits_3(string str,int k){
    int tlen=str.length();
    vector<string> nums(k+1);
    string s1,s2,last;
    for(int i=1;i<=tlen;i++){
        for(int j=0;j<i && j<=k;j++){
            if(j==0){
                last=nums[j];
                nums[j]=str.substr(0,i);
            }
            else{
                // s1=last
                s1=nums[j-1];
                s2=nums[j]+str[i-1];
                if(s1.compare(s2)<=0){
                    last=nums[j];
                    nums[j]=s2;
                }
                else{
                    last=nums[j];
                    nums[j]=s1;
                }
            }
        }
    }
    return nums[k];
}

// dynamic programming
// time complexity: O(n*k)
// space complexity: O(k)
string deleteKBits_4(string str,int k){
    int tlen=str.length();
    vector<string> nums(k+1);
    string tmp,s2,last;
    for(int i=1;i<=tlen;i++){
        for(int j=0;j<i && j<=k;j++){
            if(j==0){
                last=nums[j];
                nums[j]=str.substr(0,i);
            }
            else{
                // s1=last
                // s1=nums[j-1];
                s2=nums[j]+str[i-1];
                if(last.compare(s2)<=0){
                    last=nums[j];
                    nums[j]=s2;
                }
                else{
                    tmp=nums[j];
                    nums[j]=last;
                    last=tmp;
                }
            }
        }
    }
    return nums[k];
}

运行结果:

int main()
{
    string str="2319274";
    int k=3;
    cout <<deleteKBits_1(str,k)<< endl;
    cout <<deleteKBits_2(str,k)<< endl;
    cout <<deleteKBits_3(str,k)<< endl;
    cout <<deleteKBits_4(str,k)<< endl;
    return 0;
}

 

时间: 2024-10-27 08:25:40

(笔试题)删除K位数字的相关文章

算法46----移除K位数字

一.题目:移除K位数字 给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k. num 不会包含任何前导零. 示例 1 : 输入: num = "1432219", k = 3 输出: "1219" 解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219. 示例 2 : 输入: num = "10200", k = 1 输出: "

删除K个数字后的最小值(贪心算法实现)

给出一个整数,从该整数中去掉k个数字,要求剩下的数字形成的新整数尽可能小.应该如何选取被去掉的数字? 其中,整数的长度大于或等于k,给出的整数的大小可以超过long类型的数字范围. 思路: 把原整数的所有数字从左到右进行比较,如果发现某一位数字大于它右面的数字,那么在删除该数字之后,必然会使该数位的值降低.这种求局部最优解,最终得到全局最优解的思想,叫作“贪心算法”. 如果要删除k个数字,那么将遍历数字作为外层循环,以k作为外层循环,再结合栈的使用.将遍历的数字逐个入栈,遇到入栈进来的数字小于栈

【LeetCode】402、移除K位数字

1.移除K位数字 题目:402. 移掉K位数字 题目描述: ??给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小.(num 的长度小于 10002 且 ≥ k. num 不会包含任何前导零.) 示例 : 输入: num = "1432219", k = 3 输出: "1219" 解释: 移除掉三个数字 4, 3, 和 2 形成一个新的最小的数字 1219. 输入: num = "10200", k = 1 输

[LeetCode] Remove K Digits 去掉K位数字

Given a non-negative integer num represented as a string, remove k digits from the number so that the new number is the smallest possible. Note: The length of num is less than 10002 and will be ≥ k. The given num does not contain any leading zero. Ex

Leetcode 402. 移掉K位数字

// 贪心算法,当前遇到的数,比栈顶的元素小,就将栈顶元素给弹出,直至遇到比栈顶大或者是栈为空才停止,字符串保证是一个正常的数字序列.class Solution { public: string removeKdigits(string num, int k) { std::vector<int> S;//为了遍历,因此可以用vector来进行模拟. std::string result = "";// 保存最后的结果 for(int i=0; i<num.size

【苏宁易购笔试题】冒泡排序把数字“1492586&quot;排序成&quot;9865421&quot;然后生成新的字符串。

public class Bubble { public static void main(String[] args) { // TODO Auto-generated method stub String initial = "1492586"; StringBuffer sb = new StringBuffer(""); int[] array = new int[initial.length()]; for (int i = 0; i < initi

贪心算法-移除K个数字

1.题目描述 给定一个以字符串表示的非负整数 num,移除这个数中的 k 位数字,使得剩下的数字最小. 注意: num 的长度小于 10002 且 ≥ k. num 不会包含任何前导零. 2.题目分析: 题目简介明了,就是把给定的数字删除指定个数的数字使删除之后的数字是同等位数数字中最小的那个.但是需要注意的是,题目中给的数字是字符串的形式并且输出结果也是字符串的形式,这就涉及到字符串和数字之间的相互转化问题. 题目中要求删除的数字个数是不确定的,那么我们可以根据数学知识先分析当我们删除一个数字

rqnoj 相同的后k位

题目描述 路人甲给你出了一道奇怪的问题,他给你了一个正整数L,他想知道当正整数m,n为何值时,L^m与L^n的最后K位数字相同. 路人甲考虑到可能会有很多组解,你只需要告诉他最小的m,n且0<n<m. 输入格式 一个正整数L,一个正整数k 输出格式 输出一个最小的m,n 样例输入 样例输出 注释 [数据规模及约定] 100<=L<=9999 1<=k<=4 #include<iostream> #include<cstdio> #include&

删除一个数的K位使原数变得最小

原创 给定一个n位正整数a, 去掉其中k个数字后按原左右次序将组成一个新的正整数.对给定的a, k寻找一种方案,使得剩下的数字组成的新数最小. 提示:应用贪心算法设计求解 操作对象为n位正整数,有可能超过整数的范围,存储在数组a中,数组中每一个数组元素对应整数的一位数字. 在整数的位数固定的前提下,让高位的数字尽量小,整数的值就小.这就是所要选取的贪心策略. 每次删除一个数字,选择一个使剩下的数最小的数字作为删除对象. 当k=1时,对于n位数构成的数删除哪一位,使得剩下的数据最小.删除满足如下条