自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

數(shù)據(jù)結(jié)構(gòu)與算法之單調(diào)遞增的數(shù)字

開發(fā) 前端 算法
本題只要想清楚個例,例如98,一旦出現(xiàn)strNum[i - 1] > strNum[i]的情況(非單調(diào)遞增),首先想讓strNum[i - 1]減一,strNum[i]賦值9,這樣這個整數(shù)就是89。就可以很自然想到對應(yīng)的貪心解法了。

[[439817]]

單調(diào)遞增的數(shù)字

力扣題目鏈接:https://leetcode-cn.com/problems/monotone-increasing-digits

給定一個非負(fù)整數(shù) N,找出小于或等于 N 的最大的整數(shù),同時這個整數(shù)需要滿足其各個位數(shù)上的數(shù)字是單調(diào)遞增。

(當(dāng)且僅當(dāng)每個相鄰位數(shù)上的數(shù)字 x 和 y 滿足 x <= y 時,我們稱這個整數(shù)是單調(diào)遞增的。)

示例 1:

  • 輸入: N = 10
  • 輸出: 9

示例 2:

  • 輸入: N = 1234
  • 輸出: 1234

示例 3:

  • 輸入: N = 332
  • 輸出: 299

說明: N 是在 [0, 10^9] 范圍內(nèi)的一個整數(shù)。

暴力解法

題意很簡單,那么首先想的就是暴力解法了,來我替大家暴力一波,結(jié)果自然是超時!

代碼如下:

  1. class Solution { 
  2. private: 
  3.     bool checkNum(int num) { 
  4.         int max = 10; 
  5.         while (num) { 
  6.             int t = num % 10; 
  7.             if (max >= t) max = t; 
  8.             else return false
  9.             num = num / 10; 
  10.         } 
  11.         return true
  12.     } 
  13. public
  14.     int monotoneIncreasingDigits(int N) { 
  15.         for (int i = N; i > 0; i--) { 
  16.             if (checkNum(i)) return i; 
  17.         } 
  18.         return 0; 
  19.     } 
  20. }; 
  • 時間復(fù)雜度:O(n * m) m為n的數(shù)字長度
  • 空間復(fù)雜度:O(1)

貪心算法

題目要求小于等于N的最大單調(diào)遞增的整數(shù),那么拿一個兩位的數(shù)字來舉例。

例如:98,一旦出現(xiàn)strNum[i - 1] > strNum[i]的情況(非單調(diào)遞增),首先想讓strNum[i - 1]--,然后strNum[i]給為9,這樣這個整數(shù)就是89,即小于98的最大的單調(diào)遞增整數(shù)。

這一點如果想清楚了,這道題就好辦了。

局部最優(yōu):遇到strNum[i - 1] > strNum[i]的情況,讓strNum[i - 1]--,然后strNum[i]給為9,可以保證這兩位變成最大單調(diào)遞增整數(shù)。

全局最優(yōu):得到小于等于N的最大單調(diào)遞增的整數(shù)。

但這里局部最優(yōu)推出全局最優(yōu),還需要其他條件,即遍歷順序,和標(biāo)記從哪一位開始統(tǒng)一改成9。

此時是從前向后遍歷還是從后向前遍歷呢?

從前向后遍歷的話,遇到strNum[i - 1] > strNum[i]的情況,讓strNum[i - 1]減一,但此時如果strNum[i - 1]減一了,可能又小于strNum[i - 2]。

這么說有點抽象,舉個例子,數(shù)字:332,從前向后遍歷的話,那么就把變成了329,此時2又小于了第一位的3了,真正的結(jié)果應(yīng)該是299。

所以從前后向遍歷會改變已經(jīng)遍歷過的結(jié)果!

那么從后向前遍歷,就可以重復(fù)利用上次比較得出的結(jié)果了,從后向前遍歷332的數(shù)值變化為:332 -> 329 -> 299

確定了遍歷順序之后,那么此時局部最優(yōu)就可以推出全局,找不出反例,試試貪心。

C++代碼如下:

  1. class Solution { 
  2. public
  3.     int monotoneIncreasingDigits(int N) { 
  4.         string strNum = to_string(N); 
  5.         // flag用來標(biāo)記賦值9從哪里開始 
  6.         // 設(shè)置為這個默認(rèn)值,為了防止第二個for循環(huán)在flag沒有被賦值的情況下執(zhí)行 
  7.         int flag = strNum.size(); 
  8.         for (int i = strNum.size() - 1; i > 0; i--) { 
  9.             if (strNum[i - 1] > strNum[i] ) { 
  10.                 flag = i; 
  11.                 strNum[i - 1]--; 
  12.             } 
  13.         } 
  14.         for (int i = flag; i < strNum.size(); i++) { 
  15.             strNum[i] = '9'
  16.         } 
  17.         return stoi(strNum); 
  18.     } 
  19. }; 
  • 時間復(fù)雜度:O(n) n 為數(shù)字長度
  • 空間復(fù)雜度:O(n) 需要一個字符串,轉(zhuǎn)化為字符串操作更方便

總結(jié)

本題只要想清楚個例,例如98,一旦出現(xiàn)strNum[i - 1] > strNum[i]的情況(非單調(diào)遞增),首先想讓strNum[i - 1]減一,strNum[i]賦值9,這樣這個整數(shù)就是89。就可以很自然想到對應(yīng)的貪心解法了。

想到了貪心,還要考慮遍歷順序,只有從后向前遍歷才能重復(fù)利用上次比較的結(jié)果。

最后代碼實現(xiàn)的時候,也需要一些技巧,例如用一個flag來標(biāo)記從哪里開始賦值9。

其他語言版本

Java:

  1. 版本1 
  2. class Solution { 
  3.     public int monotoneIncreasingDigits(int N) { 
  4.         String[] strings = (N + "").split(""); 
  5.         int start = strings.length; 
  6.         for (int i = strings.length - 1; i > 0; i--) { 
  7.             if (Integer.parseInt(strings[i]) < Integer.parseInt(strings[i - 1])) { 
  8.                 strings[i - 1] = (Integer.parseInt(strings[i - 1]) - 1) + ""
  9.                 start = i; 
  10.             } 
  11.         } 
  12.         for (int i = start; i < strings.length; i++) { 
  13.             strings[i] = "9"
  14.         } 
  15.         return Integer.parseInt(String.join("",strings)); 
  16.     } 

java版本1中創(chuàng)建了String數(shù)組,多次使用Integer.parseInt了方法,這導(dǎo)致不管是耗時還是空間占用都非常高,用時12ms,下面提供一個版本在char數(shù)組上原地修改,用時1ms的版本

  1. 版本2 
  2. class Solution { 
  3.     public int monotoneIncreasingDigits(int n) { 
  4.         if (n==0)return 0; 
  5.         char[] chars= Integer.toString(n).toCharArray(); 
  6.         int start=Integer.MAX_VALUE;//start初始值設(shè)為最大值,這是為了防止當(dāng)數(shù)字本身是單調(diào)遞增時,沒有一位數(shù)字需要改成9的情況 
  7.         for (int i=chars.length-1;i>0;i--){ 
  8.             if (chars[i]<chars[i-1]){ 
  9.                 chars[i-1]--; 
  10.                 start=i; 
  11.             } 
  12.         } 
  13.         StringBuilder res=new StringBuilder(); 
  14.         for (int i=0;i<chars.length;i++){ 
  15.             if (chars[i]=='0'&&i==0)continue;//防止出現(xiàn)09這樣的情況 
  16.             if (i>=start){ 
  17.                 res.append('9'); 
  18.             }else res.append(chars[i]); 
  19.         } 
  20.         return Integer.parseInt(res.toString()); 
  21.     } 

Python:

  1. class Solution: 
  2.     def monotoneIncreasingDigits(self, n: int) -> int
  3.         a = list(str(n)) 
  4.         for i in range(len(a)-1,0,-1): 
  5.             if int(a[i]) < int(a[i-1]): 
  6.                 a[i-1] = str(int(a[i-1]) - 1) 
  7.                 a[i:] = '9' * (len(a) - i)  #python不需要設(shè)置flag值,直接按長度給9就好了 
  8.         return int("".join(a)) 

Go

  1. func monotoneIncreasingDigits(N intint { 
  2.     s := strconv.Itoa(N)//將數(shù)字轉(zhuǎn)為字符串,方便使用下標(biāo) 
  3.     ss := []byte(s)//將字符串轉(zhuǎn)為byte數(shù)組,方便更改。 
  4.     n := len(ss) 
  5.     if n <= 1 { 
  6.         return N 
  7.     } 
  8.     for i:=n-1 ; i>0; i-- { 
  9.         if ss[i-1] > ss[i] {//前一個大于后一位,前一位減1,后面的全部置為9 
  10.             ss[i-1] -= 1 
  11.             for j := i ; j < n; j++ {//后面的全部置為9 
  12.                 ss[j] = '9' 
  13.             } 
  14.         } 
  15.     } 
  16.     res, _ := strconv.Atoi(string(ss)) 
  17.     return res 

Javascript

  1. var monotoneIncreasingDigits = function(n) { 
  2.     n = n.toString() 
  3.     n = n.split('').map(item => { 
  4.         return +item 
  5.     }) 
  6.     let flag = Infinity 
  7.     for(let i = n.length - 1; i > 0; i--) { 
  8.         if(n [i - 1] > n[i]) { 
  9.             flag = i 
  10.             n[i - 1] = n[i - 1] - 1 
  11.             n[i] = 9 
  12.         } 
  13.     } 
  14.  
  15.     for(let i = flag; i < n.length; i++) { 
  16.         n[i] = 9 
  17.     } 
  18.  
  19.     n = n.join(''
  20.     return +n 
  21. }; 

 

責(zé)任編輯:姜華 來源: 代碼隨想錄
相關(guān)推薦

2020-10-30 09:56:59

Trie樹之美

2022-09-21 07:57:33

二叉搜索樹排序二叉樹

2022-09-26 07:56:53

AVL算法二叉樹

2020-12-31 05:31:01

數(shù)據(jù)結(jié)構(gòu)算法

2020-10-21 14:57:04

數(shù)據(jù)結(jié)構(gòu)算法圖形

2023-03-08 08:03:09

數(shù)據(jù)結(jié)構(gòu)算法歸并排序

2020-10-20 08:14:08

算法與數(shù)據(jù)結(jié)構(gòu)

2020-10-12 11:48:31

算法與數(shù)據(jù)結(jié)構(gòu)

2022-01-18 19:13:52

背包問題數(shù)據(jù)結(jié)構(gòu)算法

2023-10-27 07:04:20

2023-04-27 09:13:20

排序算法數(shù)據(jù)結(jié)構(gòu)

2021-12-21 11:39:01

數(shù)據(jù)結(jié)構(gòu)算法同構(gòu)字符串

2009-08-11 14:43:42

C#數(shù)據(jù)結(jié)構(gòu)與算法

2021-12-08 11:31:43

數(shù)據(jù)結(jié)構(gòu)算法合并區(qū)間

2021-07-16 04:57:45

Go算法結(jié)構(gòu)

2009-08-11 14:51:11

C#數(shù)據(jù)結(jié)構(gòu)與算法

2023-03-07 08:02:07

數(shù)據(jù)結(jié)構(gòu)算法數(shù)列

2023-03-02 08:15:13

2023-03-10 08:07:39

數(shù)據(jù)結(jié)構(gòu)算法計數(shù)排序

2009-08-11 14:30:32

C#數(shù)據(jù)結(jié)構(gòu)與算法
點贊
收藏

51CTO技術(shù)棧公眾號