leetcode964 表示數字的最少運算子

2021-09-26 16:32:26 字數 3165 閱讀 4125

給定乙個正整數 x,我們將會寫出乙個形如 x (op1) x (op2) x (op3) x … 的表示式,其中每個運算子 op1,op2,… 可以是加、減、乘、除(+,-,*,或是 /)之一。例如,對於 x = 3,我們可以寫出表示式 3 * 3 / 3 + 3 - 3,該式的值為 3 。

在寫這樣的表示式時,我們需要遵守下面的慣例:

除運算子(/)返回有理數。

任何地方都沒有括號。

我們使用通常的操作順序:乘法和除法發生在加法和減法之前。

不允許使用一元否定運算子(-)。

例如,「x - x」 是乙個有效的表示式,因為它只使用減法,但是 「-x + x」 不是,因為它使用了否定運算子。

我們希望編寫乙個能使表示式等於給定的目標值 target 且運算子最少的表示式。返回所用運算子的最少數量。

示例 1:

輸入:x = 3, target = 19

輸出:5

解釋:3 * 3 + 3 * 3 + 3 / 3 。表示式包含 5 個運算子。

示例 2:

輸入:x = 5, target = 501

輸出:8

解釋:5 * 5 * 5 * 5 - 5 * 5 * 5 + 5 / 5 。表示式包含 8 個運算子。

示例 3:

輸入:x = 100, target = 100000000

輸出:3

解釋:100 * 100 * 100 * 100 。表示式包含 3 個運算子。

1、踩過的坑

這是一道很明顯的動態規劃問題,一開始我只是把這題當成一般的動態規劃問題,結果。。。

當時是這麼想的,既然要把這個target拆成用x表達的計算式,那麼不妨從最高位開始,舉個例子:

輸入:x = 5, target = 501

輸出:8

解釋:5 * 5 * 5 * 5 - 5 * 5 * 5 + 5 / 5 。表示式包含 8 個運算子。

實際上也可以從125(5*5*5)開始做加法式的計算:

5 * 5 * 5 + 5 * 5 * 5 + 5 * 5 * 5 + 5 * 5 * 5 + 5 / 5

不過這麼做顯然不妥。因為運算子數量不是最少的。

於是我得出結論,每次給出乙個target,需要計算的時候,都有兩個方向:

只要能夠求出兩個方向中較小的值,就能得出答案

求解方法是直接遞迴地求解加(減)之後的target了,還是以上面的例子為例:

如果我從減法方向入手:

首先求出625,然後減去target,得124,這就是我要求的新的target,直接遞迴求解

當target小於x時,不必遞迴直接算出答案

實際上不行,因為每次計算都涉及到兩個方向,一加一減,有大量的重複,甚至出現自己呼叫自己的情況:

輸入:x = 5, target = 375

第一次做減法得:625 - 375 = 250

第二次做減法得:625 - 250 = 375

這個自己呼叫自己的情況,是有條件出現的,我做了一點改進,使得每次做加法或者減法時都要看看裡哪個方向更近,走近的路,可以避免這個錯誤

c++**:

class solution 

long max_num = computepow(x, target);

if(table.count(target))

return table[target];

long num_up = x * x, num_low = x;

long mid = (num_up + num_low) / 2;

for(long i = 2 * x; i <= target + x; i += x)

else

table.insert(map::value_type(i, temp));

}else

}if(table.count(target))

return table[target];

mid = (num_up + num_low) / 2;

int ans;

if(true)

if(true)

ans = (ans > ans3) ? ans3 : ans;

}return ans;

}long computepow(int& x, int& target)

table.insert(map::value_type(num, n));

return num;}};

這個**也是錯的,雖然例子過了,但是還是錯了

這是因為:離的近那一方,雖然從數值上來看較小,但是使用x來表示,其代價不一定比離得遠的那一方大

於是,我們還是應該從兩個方向入手,不過在加法方向上需要設定限制,以免無窮無盡的加

這裡,我們採用除法而不是乘法,來避免數值溢位

舉個例子:

輸入:x = 5, target = 501

第一次,通過加法或者減法(5的0次方),使target變為5的倍數(即:500或者505)

第二次,通過加法或者減法(5的1次方),使target變為5 * 5的倍數

.......

如此下去,因為每次計算都有加減兩個方向,減法方向經過數次計算會變為0,到達遞迴出口,但是加法不會,而且還有數值溢位的風險

因此每次計算後,我們將指數+1,而將target除以5,來表示下一次

c++**:

class solution 

// 動態規劃

964 表示數字的最少運算子

給定乙個正整數x,我們將會寫出乙個形如x op1 x op2 x op3 x 的表示式,其中每個運算子op1,op2,可以是加 減 乘 除 或是 之一。例如,對於x 3,我們可以寫出表示式3 3 3 3 3,該式的值為 3 在寫這樣的表示式時,我們需要遵守下面的慣例 除運算子 返回有理數。任何地方都...

華為OJ 表示數字

表示數字 將乙個字元中所有出現的數字前後加上符號 其他字元保持不變 public static string marknum string pinstr 輸入描述 輸入乙個字串 輸出描述 字元中所有出現的數字前後加上符號 其他字元保持不變 輸入例子 jkdi234klowe90a3 輸出例子 jkd...

java 數字的內部表示

byte 128 to 127 27 to 27 1 整數的表達 原碼 第一位為符號位 0為正數,1為負數 反碼 符號位不動,原碼取反 負數補碼 符號位不動,反碼加1 正數補碼 和原碼相同 例如 5 原始碼是00000101,補碼也是00000101。6 原始碼是 10000110,反碼也是 111...