402.Remove K Digits(删去k个数字后的最小值)精解

题目:Remove K Digits

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.
Example 1:

Input: num = "1432219", k = 3
Output: "1219"
Explanation: Remove the three digits 4, 3, and 2 to form the new number 1219 which is the smallest.
Example 2:

Input: num = "10200", k = 1
Output: "200"
Explanation: Remove the leading 1 and the number is 200. Note that the output must not contain leading zeroes.
Example 3:

Input: num = "10", k = 2
Output: "0"
Explanation: Remove all the digits from the number and it is left with nothing which is 0.

分析:

题目是LeetCode上的一个题目:
大意就是:有一个数字(个数>K),删掉其中的 K 个数字,使组成的新的数字最小。

小注:数字的长度很长,用String型存贮,输出的数字不以0开始。

一开始以为是从按照数字的大到小进行删除,但是举例子发现并不是这么简单。

例子:2159 删掉一个数,删掉9是215,删掉2是159。 明显删掉2比9的结果更小。分析得结论是数字的位置比数字的大小更重要。

应该是从高位向低位检索,用比自己小的数来替换自己的位置。 可以理解为若是右边的比左边的小,则删除左边的。

这是每一步求的局部最优解,最终得到全局最优解,也是贪心算法的思想。

这是第一次在LeetCode上做题,emmmm,每一次提交的错误信息都会告诉你,这个很贴心。

先放一个我的错误代码

class Solution {
//思路有问题
    public String removeKdigits(String num, int k) {
		String newString = "";
		char temp[] = new char[num.length()];
		for (int i = 0; i < num.length(); i++)
			temp[i] = num.charAt(i);
		int count = k;//删减次数
		//若长度和k相同,直接返回0
		if (num.length() == k)
			return "0";
		else {
		//只遍历一次,也是错误的地方
			for (int i = 0; i < num.length(); i++) {
				if (count > 0) {
				   if (i < num.length() - 1) {
					 if (temp[i] <= temp[i + 1]) {
						//若是左边比不比右边,则加到新的串里去
						newString += temp[i];
					  } else
					    //否则就删掉这个数
						count--;
					}else  {
					//当i到了最后一个数,无法比较,直接加进去
						newString += temp[i];
					}
				} else {
				若是count等于零了,剩下的全部加进去
					newString += temp[i];
				}
			}
		}		
		int zero=0;//判断一开始等于零的个数
		for(int x=0;x<newString.length();x++) {
			if(newString.charAt(x)!='0')
				break;
			else 
				zero++;		
		}
		//若是比较之后count不等于0,则从后向前删掉
			newString=newString.substring(zero, newString.length()-count);
			if(newString.length()==0)
				return "0";		
		return newString;
    }
}

在这里插入图片描述

改进

这时候出的问题是,我发现,添加一个新的字符串是不对的,因为一次循环是解决不了问题的。像上面的例子,我一次遍历后,删掉9,然后都加入了字符串,从后向前删除。最后只剩下了1。

应该采用删除的思路,将不合格的字符从字符串中删掉。

class Solution {
    public String removeKdigits(String num, int k) {
		char temp[] = new char[num.length()];
		int count = k;
		int time=0;
		if (num.length() == k)
			return "0";
		else {
			int max=num.length();
			Loop:for(int j=0;j<max;j++) {
				for (int i = 0; i < num.length(); i++) {
				  if (count > 0) {
					if (i < num.length() - 1) {
						//不合格的删掉
						if (num.charAt(i) > num.charAt(i+1)) {
							num=num.substring(0, i)+num.substring(i+1,num.length());
							count--;
							//下一次从前一个开始于后一个比较
							time=i-1;
							break;
						}				
					}
				}
				else 
				  break Loop;
				}
			}		
		}

		int zero = 0;
		for (int x = 0; x < num.length(); x++) {
			if (num.charAt(x) != '0')
				break;
			else
				zero++;
		}
		num = num.substring(zero, num.length() - count);
		if (num.length() == 0)
			return "0";
		return num;

	}
}

在这里插入图片描述
只能说尬的一批,提交中是垫底了,需要优化。
这个代码中,每一次变化都是在用subString方法,效率巨慢,而且循环也浪费了时间。

借鉴大佬的算法

采用栈,每次都和栈顶元素进行比较,比栈顶元素小,则栈顶元素出栈,继续与栈顶比较,若大于栈顶,则入栈

class Solution {
    public String removeKdigits(String num, int k) {
		// 新整数的最终长度 = 原整数长度 - k
		int newLength = num.length() - k;
		// 创建一个栈,用于接收所有的数字
		char[] stack = new char[num.length()];
		int top = 0;
		for (int i = 0; i < num.length(); ++i)
		{
           // 遍历当前数字
			char c = num.charAt(i);
           // 当栈顶数字大于遍历到的当前数字,栈顶数字出栈(相当于删除数字),直到栈顶小于待加入的数字
			while (top > 0 && stack[top - 1] > c && k > 0) {
				top -= 1;
				k -= 1;
			}
            // 待加入的数字入栈
			stack[top++] = c;
		}
         // 找到栈中第一个非零数字的位置
		int offset = 0;
		while (offset < newLength && stack[offset] == '0')
			offset++;

        //返回新建的字符串对象,用栈中的元素组成,减去零的长度
		return offset == newLength ? "0" : new String(stack, offset, newLength - offset);
	}
}

在这里插入图片描述

总结:

大神就是大神,就是牛逼,不过这样的逻辑依旧只能84%,很是好奇其他的代码是啥样的。
继续努力。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值