Leetcode171-190刷題筆記(非困難題)
171.Excel表列序號
該題目就有點類似於一個進位為26的一個進位制轉換的題目。
public int titleToNumber(String s) {
int ans = 0;
for(int i=0; i<s.length(); i++) {
ans *= 26;
ans += s.charAt(i) - 'A' + 1;
}
return ans;
}
172.階乘後的零個數
該題目暴力法可以解決,但是題目要求我們使用logn查詢,那說明一定是存在一些情況我們可以進行一些省略。
就比如說我們需要找到階乘計算後零的個數,我們可以通過換個思考方式。
什麼樣的情況會出現零?
那就是類似於 2 * 5 / 4 * 10 這樣的情況,我們也可以發現最基礎的情況就是 2 * 5,那麼我們可以尋找兩個數中一共有多少對 2 * 5,換句話說也就是找兩個數的因子了。
2的因子很好找,因為階乘是 1 * 2 * …n,所以每一個偶數就可以作為因子,而5呢也就是10個裡面有兩個,所以我們可以發現其實5的個數源遠少於2的個數,所以我們其實只需要統計在這個階乘計算中,一共可以分離出多少個5就行了。
知道上面那個思想直接寫程式碼。
//階乘有多少個 0
public int trailingZeroes(int n) {
//構成10的結構 2 * 5 這樣的形式,可以構成一個 10
int ans = 0;
//通常 2 的出現數量比 5 多(這裡的數字都是作為因子的存在),所以我們每次 + 5可以提高速度
for(int i=5; i<=n; i+=5) {
//階乘構成也可能存在多個 5 (例如25,125),所以針對這種情況我們需要進行多次迴圈處理
int curr = i;
while(curr % 5 == 0) { //更夠被5整除
ans += 1;
curr /= 5;
}
}
return ans;
}
173.二叉搜尋樹迭代器
題目要求我們的空間複雜度為O(H),H為樹的高度。
這個空間複雜度的限制,讓我們覺得可能需要使用一個棧,並且棧內最多存放的就是一條數到葉子結點的路徑。
這個思路讓我們想到了之前的二叉樹的中序遍歷的迭代版本。使用的是一個模擬的思想。
我們先將所有左子樹入棧(二叉搜尋樹,左子樹一定小於父節點),出棧的時候我們通過判斷結點是否擁有右子樹,如果存在右子樹,則下一個最小值一定存在於右子樹中(二叉搜尋樹性質,右子樹的結點一定大於父節點,但是一定小於父節點的父節點),所以我們則將右子樹部分按照之前的方法入棧(即入棧左子樹部分)。
//二叉搜尋樹迭代器
class BSTIterator {
private Stack<TreeNode> stack = new Stack<>();
public BSTIterator(TreeNode root) {
//左子樹的左節點全部入棧
while (root != null) {
stack.push(root);
root = root.left;
}
}
//返回下一位的最小的數
public int next() {
//彈出棧頂
TreeNode pop = stack.pop();
//如果有右子樹,則按照初始化方式入棧
if(pop.right != null) {
TreeNode root = pop.right;
while(root != null) {
stack.push(root);
root = root.left;
}
}
return pop.val;
}
public boolean hasNext() {
return stack.isEmpty();
}
}
179.最大數
該題目就是一個比較兩個數誰應該放在前面的題目。
例如 [5,34],自然是534>345,所以我們可以發現排序方式是字典序排序,但是也有特殊情況。
例如[10,2],雖然是210>102,但是2的字典序 > 10的字典序,所以說不能用簡單的字典序排序。
我們這裡使用的是將兩中組合情況列舉出來進行排序,使用比較器Compator。
需要注意的是,如果第一位為0,那麼說明整個陣列都為0,因為任意非0的數和0組合0一定在後面的,比如[0,1],一定是10>01。
public String largestNumber(int[] nums) {
List<String> list = new ArrayList<>();
for(int num : nums) {
list.add(num + "");
}
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//o1在前面
String s1 = o1 + o2;
//o2在前面
String s2 = o2 + o1;
// s1(o1在前面)字典序大則說明構成的數也大,說明o1應該放在前面,即小於情況
return -s1.compareTo(s2);
}
});
StringBuilder stringBuilder = new StringBuilder();
//如果此時第一位還是0,說明全部都是0
//因為任意非0數和0組合,0一定在最後面。
if(list.get(0).equals("0")) {
return "0";
}
for(String s : list) {
//開頭不允許為 0
stringBuilder.append(s);
}
return stringBuilder.toString();
}
187.重複的DNA序列
題目要求是一個長度為10的DNA片段,並且出現次數 > 1。
所以通過這句話我們可以直接發現這是一個滑動視窗的問題,並且明確告訴了視窗長度為10。
則我們通過Set集合,判斷是否出現重複即可,重複則放入我們需要的ans中,需要注意的是結果集最好使用Set,因為可能出現多次DNA片段,但我們只需要新增一次即可。
//重複的DNA
public List<String> findRepeatedDnaSequences(String s) {
Set<String> ans = new HashSet<>();
Set<String> set = new HashSet<>();
for(int i=0; i<=s.length()-10; i++) {
String target = s.substring(i,i+10);
if(set.contains(target)) {
ans.add(target);
}else {
set.add(target);
}
}
return new ArrayList<>(ans);
}
189.旋轉陣列
該題目我們可以選擇暴力法解決,就是每次旋轉一次都將最後一位儲存,並且將第一位騰空,在賦值過去,時間複雜度 O(N * K)
有一種比較巧的辦法就是通過三次陣列反轉的方式完成的。
[1,2,3,4,5,6,7] k = 3
1.反轉整個陣列。[7,6,5,4,3,2,1]
2.反轉前k-1個陣列。[5,6,74,3,2,1]
3.反轉剩餘陣列。[5,6,7,1,2,3,4]
但是需要注意的是:
1、如果陣列長度為 1 ,那麼反轉就無意義。
2、如果反轉次數 > 陣列長度。說明有冗餘次數,沒旋轉一個陣列長度後陣列和原陣列無差別(一個週期),所以為了避免我們選擇將k與陣列長度取餘。
//旋轉陣列,順時針,k為旋轉次數
public void rotate(int[] nums, int k) {
//只有一個元素,沒有反轉的意義
if(nums.length == 1) {
return;
}
//反轉陣列長度為一個週期, 多個週期也無意義
k %= nums.length;
//整體反轉
reverse(nums,0,nums.length-1);
//反轉前k個
reverse(nums,0,k-1);
//反轉剩餘部分
reverse(nums,k,nums.length-1);
}
public void reverse(int[] nums, int left, int right) {
while(left < right) {
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
left++;
right--;
}
}
190.顛倒二進位制位
有點類似於陣列的反轉,只不過這裡是二進位制的反轉。
這裡使用的是位操作,通過每次獲取n的最低位的情況(是 0/1,通過 n & 1獲得),加上對應的位數結果,達到反轉的效果,需要記得將結果左移,將n右移。
//顛倒二進位制,類似於二進位制的反轉
public int reverseBits(int n) {
int ans = 0;
for(int i=0; i<32; i++) {
//ans左移
ans <<= 1;
//獲得n的最低位,作為ans的最高位
ans += n & 1;
//n右移
n >>= 1;
}
return ans;
}
191.二進位制中1的個數
是位運算章節的題目,我們需要對二進位制中的 1 進行計數,可以通過使用一個mask用於和二進位制中最右邊的未檢測的位進行與運算(如果二進位制中為0則與的結果為0,否則為1即將計數器++),之後再講mask左移一位,使其能和下一位進行與運算判斷。
//二進位制中 1 的個數
public int hammingWeight(int n) {
int ans = 0;
int mask = 1;
for(int i=0; i<32; i++) {
//說明二進位制對應位為1,計數器 +1
if((n & mask) != 0) {
ans++;
}
mask <<= 1;
}
return ans;
}
相關文章
- 力扣前1500道非會員題刷題筆記力扣筆記
- leetcode刷題筆記LeetCode筆記
- 刷題筆記02筆記
- 刷題筆記03筆記
- LeetCode 刷題筆記LeetCode筆記
- 【LeetCode刷題(困難程度)】132. 分割回文串 IILeetCode
- noip刷題筆記1筆記
- 【刷題筆記】2024.10.4 test筆記
- leetcode刷題筆記605LeetCode筆記
- 一些困難題
- leetcode刷題筆記(3)(python)LeetCode筆記Python
- 想轉行遇到刷題困擾
- ctfshow_web_1(困難題)Web
- leetcode刷題筆記8.5-8.9LeetCode筆記
- Leetcode刷題筆記8.12-8.16LeetCode筆記
- LeetCode刷題筆記9.2-9.9LeetCode筆記
- Codeforces 800-1300 刷題筆記筆記
- (刷題筆記)軟考中級資料庫 上午題筆記資料庫
- ✏️ JavaScript版 | 10大專題 | 劍指offer刷題筆記 ✏️JavaScript筆記
- 如何解決MES交付困難問題?
- 【筆記】非傳統題選講 2024.8.5筆記
- 刷題記錄
- 劍指Offer系列刷題筆記彙總筆記
- 力扣刷題Python筆記:括號生成力扣Python筆記
- 刷題記錄:劍指offer+遇到的筆試題+LeetCode筆試LeetCode
- 2024.07.27科大訊飛(有困難題)
- 力扣刷題筆記:207. 課程表力扣筆記
- LeetCode刷題記錄LeetCode
- 刷題記錄11
- 記錄刷題日常
- Codeforces 刷題記錄
- BUU刷題記錄
- CTF刷題記錄
- 刷題記錄24
- 刷題記錄27
- 2018年前端面試題記錄(非高難度)前端面試題
- 安卓應用安全指南六、困難問題安卓
- 【刷題筆記】LeetCode-53 最大子陣列和筆記LeetCode陣列