1. 程式人生 > >演算法課第6周第1題——402. Remove K Digits

演算法課第6周第1題——402. 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.

程式程式碼:

class Solution {
public:
	string removeKdigits(string num, int k) {
		int len = num.size();
		// 用一個雙向佇列幫助完成演算法
		deque<int> q;
		// total為去掉k個字元後剩餘的字元總數(k表示需要去掉的字元數)
		int total = len - k;

		// 若串長度<=k, 直接輸出0
		if (len <= k) {
			string res = "0";
			return res;
		}
		
		// 遍歷
		for (int i = 0; i < len; i++) {
			// 若雙向佇列隊尾的元素比當前訪問的字元更大,則將其去掉,並將需要去掉的字元數量-1(即k-1)
			// 迴圈,直到佇列為空,或隊尾元素不會比當前訪問元素更大,或是k == 0(即不需要再去掉字元了)
			while (k != 0 && !q.empty() && q.back() > num[i]) {
				q.pop_back();
				k--;
			}
			// 將當前訪問元素放入隊尾(有可能會多出來,之後再處理)
			q.push_back(num[i]);
		}

		// 將佇列中元素放入一個字串
		// 此外,只需要放入佇列中前total個元素即可,多餘的後面部分捨棄掉即可
		string res = "";
		for (int i = 0; i < total; i++) {
			res += q.front();
			q.pop_front();
		}

		// 去除結果開頭的0
		int j = 0;
		while (res[j] == '0') {
			j++;
		}
		res = res.substr(j);

		// 至少要輸出一個“0”而不是空串
		if (res == "") {
			res = "0";
		}

		return res;
	}
};
簡要題解:

本題依舊用到了這兩週所學的貪心演算法。

先理解題意。根據題目描述及所給例子可以看出,本題是要我們去掉一個字串中的k個字元,使剩下的字元為可能的最小值。需要注意兩點,一是最後結果前的0不需要輸出,二是如果k與字串總長度相等,則要輸出0.

考慮如何解這個題目。按常規的方法來想,可以通過遍歷整個陣列,每次如果發現某個字元比它的前一個字元更大,則將這個字元刪去,然後重頭開始迴圈;若沒有符合條件的字元,則在遍歷到最後時將末尾字元刪去,並重頭開始迴圈。這整個操作重複k次。這樣就可以得到題目要求的答案。不過這種演算法每刪除一個字元就要再重頭遍歷一次,顯然時間複雜度會比較大。

考慮進一步優化貪心演算法。可以使用一個雙向佇列來輔助完成。遍歷整個字串,將每個字元都放入雙向佇列尾部,不過在放入之前,先要判斷(若雙向佇列不為空的話)雙向佇列尾部的字元是否比遍歷訪問到的這個字元大,若是,則說明佇列尾部這個字元刪去的話會讓結果變小,故將其刪去,並將k-1(表示需要刪除的字元數量少了一個)重複這個操作直到佇列為空、或是隊尾字元不再比訪問到的字元更大、或是k次刪除次數全部用完(k==0)。當全部的字元都放入雙向佇列後遍歷結束。此時佇列中的元素數量有可能比題目要求的結果更多,接著只要將這個雙向佇列的前len - k 個元素放入一個空字串即可(len為原字串長度,len - k 表示刪去k個字元後剩餘的長度),佇列中後面部分的元素捨棄即可(相當於上面常規解法中的遍歷時刪除末尾字元)。最後,為了滿足輸出要求,需要將字串前面的0字首去掉,並輸出最終結果。

本題是一道結合了字串的貪心演算法問題,演算法中每次只考慮區域性的一個字元與前面字元的關係,但可以最終得出正確的結果。貪心演算法確實非常有用,不過有時也不容易想到如何使用,需要多加鞏固。

相關推薦

演算法61——402. 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

MOOC北京理工《C語言程式設計(上)》63:郵票組合

題目內容: 我們寄信都要貼郵票,在郵局有一些小面值的郵票,通過這些小面值郵票中的一張或幾張的組合,可以滿足不同郵件的不同的郵資。 現在,郵局有4種不同面值的郵票。在每個信封上最多能貼5張郵票,面值可相同,可不同。 輸入格式: 四種郵票的面值。 輸出格式: 用這四

6作業1-閏年之迴圈判斷

參照了一下網上的;第八,第十三和十四橫所代表的意思 public class LeapYearFor { /** * @param args */ public static void main(String[] args) { // TODO Auto-

C++6專案1

【題目】下面的程式存在編譯錯誤。有兩種方法可以修改,請給出這兩種修改方案,在報告中說明你傾向於用哪一種?為什麼?處理此類問題的原則是什麼?class C {private: int x; public: C(int x){this->x= x;}

演算法111——120. Triangle

題目描述: Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below. For

16專案1 驗證演算法6)堆排序

問題: /* * Copyright (c)2015,煙臺大學計算機與控制工程學院 * All rights reserved. * 檔名稱:專案1-6.cbp * 作 者:張芸嘉 *

2018-2019-1 20165332 《資訊安全系統設計基礎》6學習總結

2018-2019-1 20165332 《資訊安全系統設計基礎》第6周學習總結 教材內容總結 一.儲存技術 1,RAM分為靜態RAM和動態RAM 2.DRAM把超單元的內容發回控制器作為響應,行地址i稱為RAS請求,列地址j稱為CAS請求 3.增強的DRAM 快頁模式DRAM 擴充套件

2018-2019-1 20165201 《資訊安全系統設計基礎》6學習總結

2018-2019-1 20165201 《資訊安全系統設計基礎》第6周學習總結 內容待完善~~~ 教材學習內容總結 儘量簡單的總結一下本週學習內容 儘量不要抄書,浪費時間 看懂就過,看不懂,學習有心得的記一下 教材學習中的問題和解決過程 (一個模板:我看了這一段文字 (引用文字),有這個問題 (提

中國大學MOOC—基礎學Java語言----6程式設計——單詞長度(5分)

import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner in = new Scanner(System.in); String

MOOC北京理工《C語言程式設計(上)》51:鍛鍊身體吧

題目內容: 沫沫,灰灰和渣渣去鍛鍊身體,如果對他們跑步的距離分別只計整數 a、 b、 c,由於他們身高的差距,造成了 a<=b<=c,並且渣渣跑了N米之後就再也跑不動了。但是,按照他們事先的約定: 只有當 c*c==a*a+b*b 時,他們的鍛鍊才有效果。

MOOC清華《程式設計基礎》61:n級臺階問題(遞推法)

題目描述 下n級臺階,每步可下1級或2級臺階。那麼從n級臺階下到地面,共有多少種不同的下臺階方案? 輸入:n 輸出:方案數 輸入格式 多行輸入,每一行輸入一個正整數n,表示n級臺階 輸出格式 每一行輸出n級臺階的方案數 樣例輸入 1 2 樣例輸出 1 2 D

16專案1 驗證演算法(7)歸併排序

問題: /* * Copyright (c)2015,煙臺大學計算機與控制工程學院 * All rights reserved. * 檔名稱:專案1-7.cbp * 作 者:張芸嘉 * 完成日期:2015年12月18日 * 版 本 號

多型與虛擬函式-程式設計#2(C++程式設計6)

程式設計題#2 來源: POJ (Coursera宣告:在POJ上完成的習題將不會計入Coursera的最後成績。) 注意: 總時間限制: 1000ms 記憶體限制: 65536kB 描述 下面

11專案1——二叉樹演算法驗證

問題及程式碼:/* *Copyright(c++)2015,煙臺大學計算機與控制工程學院 *All rights reserved. *檔名稱:CPP1.cpp *作者:宋 晨 *完成

12專案1 圖基本演算法

問題: /*  * Copyright (c)2015,煙臺大學計算機與控制工程學院  * All rights reserved.  * 檔名稱:專案1.cpp  * 作    者:張芸嘉  * 完成日期:2015年11月23日  * 版 本 號:v1.0    * 問題

61講簡單的循環結構

3-9 log 結構 -1 mar src () col pan main() { int sum,i; sum=0; i=1; while(i<=100) { sum=sum+i;

6作業

浮點型 color 強制 pri class 解決方法 -s span family 學習內容總結 題目7-1 高速公路超速處罰 1 #include<stdio.h> 2 int main() 3 { 4 int a,b; 5 fl

Linux學習筆記三次(2月7日)

配置 學習筆記 使用 con log 搜索 su命令 去掉 start 3.7 su命令root用戶切換到普通用戶命令,su;完全徹底切換 - ,連環境變量,家目錄也切換,命令為#su - aming;查看當前登陸用戶,命令為#whoami;查看當前目錄,命令為#pwd;查

Linux學習筆記四次(2月8日)

虛擬機 添加磁盤 acer cto process ued fault print rep 4.1 df命令df,report file system disk space usage匯報文件系統磁盤空間使用情況;df命令格式:df [選項]df -a:all 顯示所有文件

Linux學習筆記三次(3月7日)

yum list | grep zsh history tab鍵 alias wc -l 8.1 shell介紹每個用戶都有自己的shell;Bourne人名,為了紀念他;搜索zsh命令,#yum list | grep zsh搜索ksh命令,#yum list | grep ksh邏輯判