1. 小米筆試題——升級蓄水池html
題目描述:java
在米兔生活的二維世界中,建造蓄水池很是簡單。node
一個蓄水池能夠用n個座標軸上的非負整數表示,表明區間爲【0-n】範圍內寬度爲1的牆壁的高度。git
以下圖1,黑色部分是牆壁,牆壁的高度是[0,1,0,2,1,0,1,3,2,1,2,1] ,藍色部分是蓄水的面積,能夠看出蓄水池最大蓄水容量是6。算法
如今米兔想經過增長某些牆壁的高度對蓄水池擴容,可是經費有限,最多隻能增長最多m的高度,增長高度只能在【0-n】範圍內,高度爲0的區域也是能夠增長的,爲了追求最大的性價比,米兔想要找到一種最優方案,使擴容後蓄水池的容量最大,你能幫幫他麼?express
提示:api
對於樣例,圖2,圖3,是樣例可能的兩種擴容方案,顯然圖2是比圖3更優的方案數組
關於題目數據範圍 測試
20%的數據, n<10,m<10,蓄水池最大高度小於10spa
50%的數據, n<100,m<100,蓄水池最大高度小於100
100%的數據, n<1000,m<1000,蓄水池最大高度小於1000
輸入
第一行爲一個數字n
接下來n行,每行一個數字,表明n個牆壁的高度
最後一行爲一個數字m
輸出
一個數字,表示擴容以後蓄水池能達到的最大容量
樣例輸入
12
0
1
0
2
1
0
1
3
2
1
2
1
2
樣例輸出
12
分析
LeetCode上 trap water 題目的改進版, 當時沒有解出這題,如今回想起來能夠用dfs來遍歷全部的可能。
import java.util.*; public class LeetCode { static int maxCapicity = 0;
public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int[] array = new int[n]; for (int i = 0; i < n; i++) { array[i] = sc.nextInt(); } int m = sc.nextInt(); maxCapicity=capacity(array); dfs(0,array,m); System.out.println(maxCapicity); } static void dfs(int index, int[] array, int m) { if(index>=array.length) return; if(m==0){ maxCapicity=Math.max(maxCapicity, capacity(array)); } for (int i = 0; i <= m; i++) { array[index] += i; dfs(index + 1, array, m - i); array[index] -= i; } } static int capacity(int[] array) { int ans = 0; int n = array.length; int[] left_max = new int[n]; int[] right_max = new int[n]; left_max[0] = array[0]; right_max[n - 1] = array[n - 1]; for (int i = 1; i < array.length; i++) { left_max[i] = Math.max(left_max[i - 1], array[i]); } for (int i = array.length - 2; i >= 0; i--) { right_max[i] = Math.max(right_max[i + 1], array[i]); } for (int i = 0; i < n; i++) { ans += Math.min(right_max[i], left_max[i]) - array[i]; } return ans; } }
能解出示例的輸入,可是沒有平臺提供的測試用例因此不知道是否能經過全部的測試用例,僅供參考。
2. 嗶哩嗶哩筆試題——字符串數字表達式計算值
輸入幾行字符串形式的表達式,只包含非負整數,加號,減號和乘號,輸入其計算值。輸入以字符串END結束
輸入樣例:
3+4*5*6+4-7*4+4-2
3+4*2-1
END
輸出
101
10
分析
將原字符串按照加減號分割成字符串數組,計算每一個的實際值後再壓入棧中。以後倒序掃描原數組,遇到加號或者減號就從棧中彈出兩個數字,計算值後再壓入棧,遇到乘號則無視。最後棧中剩下的數字就是計算結果。
實際測試法發現分割後的字符串計算後的值應該倒序進棧,而後順序掃描原數組纔對,不然在計算減號時會有錯誤。
import java.util.*; public class LeetCode { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String str = sc.nextLine(); List<String> expressions = new ArrayList<>(); List<Integer> ans = new ArrayList<>(); while (!str.equals("END")) { expressions.add(str); str = sc.nextLine(); } for (String s : expressions) ans.add(calculate(s)); for (int a : ans) { System.out.println(a); } } private static int calculate(String str) { Stack<Integer> digit = new Stack<>(); String[] strs = str.split("\\+|\\-"); for (int i = strs.length - 1; i >= 0; i--) { String s = strs[i]; if (s.contains("*")) { String[] multi = s.split("\\*"); int result = 1; for (String mu : multi) result *= Integer.parseInt(mu); digit.push(result); } else { digit.push(Integer.parseInt(s)); } } for (int i = 0; i < str.length(); i++) { if (str.charAt(i) == '+' || str.charAt(i) == '-') { int num1 = digit.pop(); int num2 = digit.pop(); int result = (str.charAt(i) == '+' ? num1 + num2 : num1 - num2); digit.push(result); } } return digit.peek(); } }
3. 求旅遊完全部景點須要的最少天數
去一個地方出差,順便取旅遊,根據導遊提供的方案,每一天能夠去當地的一個景點。選擇從某一天開始本身的假期,使得在最短的天數內能去全部導遊提供的景點。
輸入示例1:(開始一個數字表示總共有多少天。而後第一列表示第幾天,第二列表示第幾天能夠去的景點編號)
7
1,7
2,5
3,1
4,7
5,2
6,5
7,1
輸出:
4
即從第2天開始假期,持續到第5天,總共4天。或者從第5天開始假期,也是4天。
輸入示例2:
11
1,2
2,3
3,1
4,3
5,3
6,7
7,2
8,2
9,1
10,1
11,3
輸出:
5,即從第3天到第7天。
分析
能夠經過循環遍歷的方式來窮舉全部的可能,不過會超時,這題關鍵時要求用有效率的方法來解。想到的法仍是根據循環遍歷而來,只不過原來的循環會有重複計算的可能,咱們要去掉這個重複計算的部分。當從以位置 i 爲起始點向後遍歷的時候,記住不一樣景點的出現次數。若是到了某一點 j 使得從 i 到 j 可以取到全部景點時,中止向後。轉而從i的下一位開始,更新當前能到達的景點的計數器,若是此時還能到達因此景點則繼續往下一位,若是不能則往 j 以後繼續遍歷直至能到達全部景點,重複這個過程便可。(我感受有點像Leetcode中Minimum Window Substring這一題的解法,額,看了一下,感受根本是一個題目 )
import java.util.*; public class LeetCode { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int n = sc.nextInt(); String[] trip = new String[n]; sc.nextLine(); for (int i = 0; i < n; i++) { String[] strs = sc.nextLine().split(","); trip[i] = strs[1]; // 數組索引直接0~n-1對應第1天到第n天
} // 先遍歷一遍肯定有幾個不一樣的景點
Set<String> spots = new HashSet<>(); for (String s : trip) { spots.add(s); } Map<String, Integer> map = new HashMap<>(); // 景點計數器,若要能到達全部景點則至少每一個景點要到達一次
for (String s : spots) { map.put(s, 0); } int begin = 0, end = 0, d = Integer.MAX_VALUE; while (end < n) { // 先從begin=0開始,找左邊第一個包含全部景點的時間段
String str = trip[end]; if (map.containsKey(str)) map.put(str, map.get(str) + 1); //檢查當前是否可以到達全部景點
boolean canTravelAll = true; for (String s : spots) { if (map.get(s) <= 0) canTravelAll = false; } //若是能夠則回到左邊,往左移縮小範圍,若是不能則繼續在右邊向後移動
while (canTravelAll) { d = Math.min(d, end - begin); // 更新最小範圍
String s = trip[begin]; map.put(s, map.get(s) - 1); // 左移後要判斷當前是否包括了全部的景點,是的話繼續左移
if (map.get(s) <= 0) canTravelAll = false; } end++; } System.out.println(d); } }
4. 寶箱怪
寶箱怪是遊戲中常見的一種怪物,它們假裝成普通的寶箱,並在被玩家打開時攻擊玩家。假設你操控的遊戲角色身處一個放着N個寶箱的房間,每一個寶箱或者是普通的寶箱,或者是寶箱怪。每一個寶箱上都貼着一張字條,字條上寫着如下兩種信息中的一種:
①第x個寶箱是普通寶箱;
②第x個寶箱是寶箱怪。
其中普通寶箱上的信息必定是真的,而寶箱怪上的信息多是假的,那麼根據這些信息,有多少個寶箱必定是普通寶箱,又有多少個寶箱必定是寶箱怪?
輸入
第一行包含一個整數N,1≤N≤105。
接下來N行,第i行包含兩個整數t和x,1≤t≤2,1≤x≤N。若t=1,則第i個寶箱上的信息爲:第x個寶箱是普通寶箱;若t=2,則第i個寶箱上的信息爲:第x個寶箱是寶箱怪
輸出
輸出兩個以空格隔開的整數,第一個整數表示能夠肯定爲普通寶箱的寶箱數量,第二個整數表示能夠肯定爲寶箱怪的寶箱數量。
樣例輸入
3
1 2
2 1
1 3
樣例輸出
0 1
分析
感受這題在測智商,就目前遇到的算法題來講,一部分時有套路的,利用dfs或者bfs,dp解之便可。有的實際上是數學問題,有的感受更像是測智商的問題。在牛客網的討論上看到一個比較靠譜的解答:https://www.nowcoder.com/discuss/118930?type=0&order=0&pos=7&page=1
首先要明確的一點是沒法肯定普通寶箱的數量的,第一個輸出數字必定是0,由於寶箱怪可能說真話也可能說假話,就算知道一個寶箱說的是真話也沒法肯定它到底時寶箱仍是寶箱怪。
因此能肯定的只多是寶箱怪,那麼怎麼肯定呢?若是從它給的結論出發,咱們一直往下推,結果獲得了矛盾的結論,那麼能夠證實它的話是假話,那麼這個寶箱即是寶箱怪。舉個例子:
寶箱1說寶箱2是普通寶箱,寶箱2說寶箱3是普通寶箱,寶箱3說寶箱1是寶箱怪。那麼若是寶箱1是普通寶箱,說的是真話,那麼能夠推出寶箱1是寶箱怪,與假設不符。那麼假設寶箱1是寶箱怪,在這種情形下,寶箱2和3說的都是真話,整個邏輯鏈下來沒問題。
即從結果往前推的話,真話推不出寶箱仍是寶箱怪,而假話能夠推出一定是寶箱怪。
因此基本的算法的思路是,先按照上面的思路肯定一遍寶箱怪,而後若是有其它寶箱說這些寶箱怪是寶箱的也一定是寶箱怪。
代碼
public class LeetCode { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int N = sc.nextInt(); sc.nextLine(); int[] types = new int[N + 1]; int[] nodes = new int[N + 1]; Set<Integer> monster = new HashSet<>(); for (int i = 1; i <= N; i++) { String[] inputs = sc.nextLine().split(" "); types[i] = Integer.parseInt(inputs[0]); nodes[i] = Integer.parseInt(inputs[1]); } int last = 0; // 遍歷判斷每一個寶箱是否是寶箱怪
for (int i = 1; i <= N; ++i) { int count = 0; int k = i; while (types[k] == 1) { k = nodes[k]; if (++count >= N) break; // 處理環
} if (types[k] == 2 && nodes[k] == i) monster.add(i); } // 指向寶箱怪 是 寶箱的 都是 寶箱怪
while (last != monster.size()) { last = monster.size(); for (int i = 1; i <= N; i++) { if (types[i] == 1 && monster.contains(nodes[i])) monster.add(i); } } System.out.println(0 + " " + monster.size()); } }