生活随笔
收集整理的這篇文章主要介紹了
力扣(简单+中等)50题整理总结
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
文章目錄 前言 一、簡單題 1. 兩數(shù)之和 7. 整數(shù)反轉(zhuǎn) 9. 回文數(shù) 13. 羅馬數(shù)字轉(zhuǎn)整數(shù) 14. 最長公共前綴 20. 有效的括號 21. 合并兩個有序鏈表 26. 刪除有序數(shù)組中的重復(fù)項 27. 移除元素 28. 實現(xiàn) strStr() 35. 搜索插入位置 38. 外觀數(shù)列 53. 最大子序和 58. 最后一個單詞的長度 66. 加一 70. 爬樓梯 101. 對稱二叉樹 110. 平衡二叉樹 118. 楊輝三角 217. 存在重復(fù)元素 219. 存在重復(fù)元素 II 283. 移動零 509. 斐波那契數(shù) 643. 子數(shù)組最大平均數(shù) I 976. 三角形的最大周長 1137. 第 N 個泰波那契數(shù) 二、中等題 2. 兩數(shù)相加 3. 無重復(fù)字符的最長子串 5. 最長回文子串 6. Z 字形變換 8. 字符串轉(zhuǎn)換整數(shù) (atoi) 17. 電話號碼的字母組合 46. 全排列 62. 不同路徑 73. 矩陣置零 94. 二叉樹的中序遍歷 130. 被圍繞的區(qū)域 144. 二叉樹的前序遍歷 145. 二叉樹的后序遍歷 198. 打家劫舍 200. 島嶼數(shù)量 445. 兩數(shù)相加 II 486. 預(yù)測贏家 503. 下一個更大元素 II 567. 字符串的排列 877. 石子游戲 總結(jié)
前言
???????從第一次進入力扣,和朋友們琢磨著第一題的兩數(shù)之和,到現(xiàn)在玩力扣有一個多學(xué)期了。雖然沒有系統(tǒng)的訓(xùn)練,但還是見識到了一些基礎(chǔ)的算法。先把做過的題總結(jié)了,然后接下來就撿一些重點算法去打。
一、簡單題
1. 兩數(shù)之和
方法:暴力,快慢指針
class Solution { public int [ ] twoSum ( int [ ] nums
, int target
) { int [ ] ans
= new int [ 2 ] ; for ( int i
= 0 ; i
< nums
. length
; ++ i
) { for ( int j
= i
+ 1 ; j
< nums
. length
; ++ j
) { if ( nums
[ j
] == target
- nums
[ i
] ) { ans
[ 0 ] = i
; ans
[ 1 ] = j
; return ans
; } } } return ans
; }
}
7. 整數(shù)反轉(zhuǎn)
方法:一位一位反轉(zhuǎn)(注意:判斷溢出)
class Solution { public int reverse ( int x
) { int ans
= 0 ; while ( x
!= 0 ) { if ( ( ans
* 10 ) / 10 != ans
) { ans
= 0 ; break ; } ans
= ans
* 10 + x
% 10 ; x
= x
/ 10 ; } return ans
; }
}
9. 回文數(shù)
方法:反轉(zhuǎn)此數(shù),判斷反轉(zhuǎn)前后是否相等
class Solution { public boolean isPalindrome ( int x
) { if ( x
< 0 ) { return false ; } int ans
= 0 , m
= x
; while ( m
!= 0 ) { ans
= ans
* 10 + m
% 10 ; m
= m
/ 10 ; } if ( x
== ans
) { return true ; } else { return false ; } }
}
13. 羅馬數(shù)字轉(zhuǎn)整數(shù)
方法:循環(huán)嵌套switch開關(guān),選擇對應(yīng)的轉(zhuǎn)換值
class Solution {
public : int romanToInt ( string s
) { int ans
= 0 ; for ( int i
= 0 ; i
< s
. size ( ) ; i
++ ) { switch ( s
[ i
] ) { case 'I' : { if ( s
[ i
+ 1 ] == 'V' ) { ans
+ = 4 ; i
++ ; break ; } if ( s
[ i
+ 1 ] == 'X' ) { ans
+ = 9 ; i
++ ; break ; } ans
+ = 1 ; } break ; case 'V' : ans
+ = 5 ; break ; case 'X' : { if ( s
[ i
+ 1 ] == 'L' ) { ans
+ = 40 ; i
++ ; break ; } if ( s
[ i
+ 1 ] == 'C' ) { ans
+ = 90 ; i
++ ; break ; } ans
+ = 10 ; } break ; case 'L' : ans
+ = 50 ; break ; case 'C' : { if ( s
[ i
+ 1 ] == 'D' ) { ans
+ = 400 ; i
++ ; break ; } if ( s
[ i
+ 1 ] == 'M' ) { ans
+ = 900 ; i
++ ; break ; } ans
+ = 100 ; } break ; case 'D' : ans
+ = 500 ; break ; case 'M' : ans
+ = 1000 ; break ; } } return ans
; }
} ;
14. 最長公共前綴
方法:按住第一個串,將其逐個字符與后面的串中對應(yīng)下標(biāo)字符比較 注意:當(dāng)首串當(dāng)前字符下標(biāo)與后面某個串的串長相等時,即可不再比較
class Solution { public String
longestCommonPrefix ( String
[ ] strs
) { if ( strs
== null
|| strs
. length
== 0 ) { return "" ; } for ( int i
= 0 ; i
< strs
[ 0 ] . length ( ) ; ++ i
) { char c
= strs
[ 0 ] . charAt ( i
) ; for ( int j
= 1 ; j
< strs
. length
; ++ j
) { if ( i
== strs
[ j
] . length ( ) || strs
[ j
] . charAt ( i
) != c
) { return strs
[ 0 ] . substring ( 0 , i
) ; } } } return strs
[ 0 ] ; }
}
20. 有效的括號
方法:左括號逐個進棧,右括號逐個與棧頂左括號匹配
關(guān)鍵點:
以棧的形式使用Deque(java) 當(dāng)左括號比右括號多時,匹配結(jié)束棧不為空
class Solution { public boolean isValid ( String s
) { Deque
< Character> stack
= new LinkedList < > ( ) ; for ( int i
= 0 ; i
< s
. length ( ) ; ++ i
) { if ( s
. charAt ( i
) == '(' || s
. charAt ( i
) == '[' || s
. charAt ( i
) == '{' ) { stack
. push ( s
. charAt ( i
) ) ; } if ( s
. charAt ( i
) == ')' ) { if ( ! stack
. isEmpty ( ) && stack
. peek ( ) == '(' ) { stack
. pop ( ) ; } else { return false ; } } else if ( s
. charAt ( i
) == ']' ) { if ( ! stack
. isEmpty ( ) && stack
. peek ( ) == '[' ) { stack
. pop ( ) ; } else { return false ; } } else if ( s
. charAt ( i
) == '}' ) { if ( ! stack
. isEmpty ( ) && stack
. peek ( ) == '{' ) { stack
. pop ( ) ; } else { return false ; } } } return stack
. isEmpty ( ) ; }
}
21. 合并兩個有序鏈表
方法:雙指針+啞元
class Solution {
public : ListNode
* mergeTwoLists ( ListNode
* l1
, ListNode
* l2
) { ListNode
* ehead
= new ListNode
; ListNode
* e
= ehead
; while ( l1
&& l2
) { if ( l1
- > val
<= l2
- > val
) { e
- > next
= l1
; l1
= l1
- > next
; } else { e
- > next
= l2
; l2
= l2
- > next
; } e
= e
- > next
; } e
- > next
= l1
== nullptr ? l2
: l1
; ehead
= ehead
- > next
; return ehead
; }
} ;
26. 刪除有序數(shù)組中的重復(fù)項
方法:快慢指針
關(guān)鍵點:
快指針負責(zé)跳過重復(fù)元素 慢指針負責(zé)把不重復(fù)的元素記錄在數(shù)組前端
class Solution {
public : int removeDuplicates ( vector
< int > & nums
) { if ( nums
. size ( ) == 0 ) return 0 ; int i
= 0 , j
, flag
= 1 ; for ( j
= i
+ 1 ; j
<= nums
. size ( ) - 1 ; ++ j
) { if ( nums
[ j
] <= nums
[ i
] ) continue ; else { nums
[ ++ i
] = nums
[ j
] ; flag
++ ; } } return flag
; }
} ;
27. 移除元素
方法:快慢指針
關(guān)鍵點:
慢指針負責(zé)找目標(biāo)val值 快指針負責(zé)將val值移動到數(shù)組后端
class Solution { public int removeElement ( int [ ] nums
, int val
) { int i
= 0 , flag
; for ( ; i
< nums
. length
; ++ i
) { if ( nums
[ i
] == val
) { flag
= 1 ; for ( int j
= i
; flag
== 1 && j
< nums
. length
; ++ j
) if ( nums
[ j
] != val
) { int temp
= nums
[ j
] ; nums
[ j
] = nums
[ i
] ; nums
[ i
] = temp
; flag
= 0 ; } if ( flag
== 1 ) break ; } } return i
; }
}
28. 實現(xiàn) strStr()
關(guān)鍵點(滑動窗口):
維護窗口起始位start 使用substring截斷進行比較
public class Solution { public int strStr ( String haystack
, String needle
) { int n
= needle
. length ( ) ; int h
= haystack
. length ( ) ; for ( int start
= 0 ; start
< h
- n
+ 1 ; start
++ ) { if ( haystack
. substring ( start
, start
+ n
) . equals ( needle
) ) { return start
; } } return - 1 ; }
}
35. 搜索插入位置
方法:暴力
class Solution { public int searchInsert ( int [ ] nums
, int target
) { for ( int i
= 0 ; i
< nums
. length
; ++ i
) { if ( nums
[ i
] < target
) { continue ; } else { return i
; } } return nums
. length
; }
}
38. 外觀數(shù)列
class Solution { public String
countAndSay ( int n
) { if ( n
== 1 ) { return "1" ; } String s
= countAndSay ( n
- 1 ) ; StringBuilder result
= new StringBuilder ( ) ; int start
= 0 ; for ( int i
= 1 ; i
< s
. length ( ) ; i
++ ) { if ( s
. charAt ( i
) != s
. charAt ( start
) ) { result
. append ( i
- start
) . append ( s
. charAt ( start
) ) ; start
= i
; } } result
. append ( s
. length ( ) - start
) . append ( s
. charAt ( start
) ) ; return result
. toString ( ) ; }
}
53. 最大子序和
關(guān)鍵點(動態(tài)規(guī)劃):
pre維護的窗口的含義
class Solution { public int maxSubArray ( int [ ] nums
) { int pre
= 0 , maxAns
= nums
[ 0 ] ; for ( int x
: nums
) { pre
= Math
. max ( pre
+ x
, x
) ; maxAns
= Math
. max ( maxAns
, pre
) ; } return maxAns
; }
}
58. 最后一個單詞的長度
方法:暴力
class Solution { public int lengthOfLastWord ( String s
) { int count
= 0 ; s
= s
. toLowerCase ( ) ; for ( int i
= s
. length ( ) - 1 ; i
>= 0 ; -- i
) { if ( s
. charAt ( i
) >= 'a' && s
. charAt ( i
) <= 'z' ) { count
++ ; } else if ( count
> 0 ) { break ; } } return count
; }
}
66. 加一
關(guān)鍵點(暴力):
因為是加1,固不進位即可返回 溢出需構(gòu)建長度為原數(shù)組長度+1的新數(shù)組,首元素初始化為1即可
class Solution { public int [ ] plusOne ( int [ ] digits
) { for ( int i
= digits
. length
- 1 ; i
>= 0 ; i
-- ) { digits
[ i
] ++ ; digits
[ i
] = digits
[ i
] % 10 ; if ( digits
[ i
] != 0 ) return digits
; } digits
= new int [ digits
. length
+ 1 ] ; digits
[ 0 ] = 1 ; return digits
; }
}
70. 爬樓梯
關(guān)鍵點(動態(tài)規(guī)劃):方程 F(n)= F(n - 1)- F(n - 2)
class Solution { public int climbStairs ( int n
) { int p
= 0 , q
= 0 , r
= 1 ; for ( int i
= 0 ; i
< n
; ++ i
) { p
= q
; q
= r
; r
= p
+ q
; } return r
; }
}
101. 對稱二叉樹
關(guān)鍵點(雙指針):
遞歸的傳參方式:check(p.left, q.right) && check(p.right, q.left) 遞歸的出口判斷:&& 要在 || 前面,幫 || 過濾兩個節(jié)點都是空的情況
class Solution { public boolean isSymmetric ( TreeNode root
) { return check ( root
, root
) ; } public boolean check ( TreeNode p
, TreeNode q
) { if ( p
== null
&& q
== null
) { return true ; } if ( p
== null
|| q
== null
) { return false ; } return p
. val
== q
. val
&& check ( p
. left
, q
. right
) && check ( p
. right
, q
. left
) ; }
}
110. 平衡二叉樹
關(guān)鍵點: 在計算二叉樹的算法基礎(chǔ)上加判斷:兩個子樹的高度絕對值是否滿足題目定義。
class Solution { public boolean isBalanced ( TreeNode root
) { return hightree ( root
) != - 1 ; } public static int hightree ( TreeNode root
) { int H
, H1
, H2
; if ( root
== null
) { H
= 0 ; } else { H1
= hightree ( root
. left
) ; H2
= hightree ( root
. right
) ; if ( H1
== - 1 || H2
== - 1 ) { return - 1 ; } if ( Math
. abs ( H1
- H2
) > 1 ) { return - 1 ; } H
= ( H1
> H2
? H1
: H2
) + 1 ; } return H
; }
}
118. 楊輝三角
關(guān)鍵點:
找規(guī)律 每次構(gòu)建answer時需重新分配其內(nèi)存 沒有搞懂第二點為什么不能用List.clear()代替
class Solution { public List
< List
< Integer> > generate ( int numRows
) { List
< List
< Integer> > answers
= new ArrayList < List
< Integer> > ( ) ; for ( int i
= 0 ; i
< numRows
; ++ i
) { List
< Integer> answer
= new ArrayList < > ( ) ; for ( int j
= 0 ; j
<= i
; ++ j
) { if ( j
== 0 || j
== i
) { answer
. add ( 1 ) ; } else { answer
. add ( answers
. get ( i
- 1 ) . get ( j
- 1 ) + answers
. get ( i
- 1 ) . get ( j
) ) ; } } answers
. add ( answer
) ; } return answers
; }
}
217. 存在重復(fù)元素
關(guān)鍵點:Set中不能添加重復(fù)元素
class Solution { public boolean containsDuplicate ( int [ ] nums
) { Set
< Integer> set
= new HashSet < Integer> ( ) ; for ( int x
: nums
) { if ( ! set
. add ( x
) ) { return true ; } } return false ; }
}
219. 存在重復(fù)元素 II
關(guān)鍵點(滑動窗口):
用Set作為滑動窗口,若窗口內(nèi)存在重復(fù)元素,則true 前進右窗:add(nums【i】),前進左窗:remove(nums【i - k】)
class Solution { public boolean containsNearbyDuplicate ( int [ ] nums
, int k
) { Set
< Integer> set
= new HashSet < Integer> ( ) ; for ( int i
= 0 ; i
< nums
. length
; ++ i
) { if ( set
. contains ( nums
[ i
] ) ) { return true ; } set
. add ( nums
[ i
] ) ; if ( set
. size ( ) > k
) { set
. remove ( nums
[ i
- k
] ) ; } } return false ; }
}
283. 移動零
關(guān)鍵點(雙指針):
一次循環(huán)代替兩次,將復(fù)雜度O(n^2)降O(n) 快指針前進的條件:遇到0或完成一次賦值
class Solution { public void moveZeroes ( int [ ] nums
) { int a
= 0 , b
= 0 ; while ( b
< nums
. length
) { if ( nums
[ b
] == 0 ) { b
++ ; continue ; } nums
[ a
++ ] = nums
[ b
++ ] ; } while ( a
< b
) { nums
[ a
++ ] = 0 ; } }
}
509. 斐波那契數(shù)
(略)
int fib ( int N
) { if ( N
== 0 ) return 0 ; if ( N
== 1 ) return 1 ; return fib ( N
- 1 ) + fib ( N
- 2 ) ;
}
643. 子數(shù)組最大平均數(shù) I
關(guān)鍵點(滑動窗口):
維護一個長度為k的窗口,在每次移動此窗口前,求窗口內(nèi)元素平均值,取Max
class Solution { public double findMaxAverage ( int [ ] nums
, int k
) { double sum
= 0 , maxAvg
= 0 ; for ( int i
= 0 ; i
< nums
. length
; ++ i
) { sum
+= nums
[ i
] ; if ( i
== k
- 1 ) { maxAvg
= sum
/ k
; } if ( i
>= k
) { sum
-= nums
[ i
- k
] ; maxAvg
= Math
. max ( sum
/ k
, maxAvg
) ; } } return maxAvg
; }
}
976. 三角形的最大周長
方法:排序、按順序找符合條件的三角形,其周長即為數(shù)組內(nèi)最大
class Solution { public int largestPerimeter ( int [ ] A
) { Arrays
. sort ( A
) ; for ( int i
= A
. length
- 1 ; i
>= 2 ; -- i
) { if ( A
[ i
- 2 ] + A
[ i
- 1 ] > A
[ i
] ) { return A
[ i
- 2 ] + A
[ i
- 1 ] + A
[ i
] ; } } return 0 ; }
}
1137. 第 N 個泰波那契數(shù)
方法:動態(tài)規(guī)劃
int tribonacci ( int n
) { if ( n
< 3 ) return n
== 0 ? 0 : 1 ; int x
= 0 , y
= 1 , z
= 1 , tep
; for ( int i
= 0 ; i
< n
- 2 ; ++ i
) { tep
= x
+ y
+ z
; x
= y
; y
= z
; z
= tep
; } return z
;
}
二、中等題
2. 兩數(shù)相加
關(guān)鍵點:雙指針,尾插,補零相加
class Solution { public ListNode
addTwoNumbers ( ListNode l1
, ListNode l2
) { ListNode head
= null
, tail
= null
; int carry
= 0 ; while ( l1
!= null
|| l2
!= null
) { int s1
= l1
== null
? 0 : l1
. val
; int s2
= l2
== null
? 0 : l2
. val
; int sum
= s1
+ s2
+ carry
; if ( head
== null
) { head
= tail
= new ListNode ( sum
% 10 ) ; } else { tail
. next
= new ListNode ( sum
% 10 ) ; tail
= tail
. next
; } carry
= sum
/ 10 ; if ( l1
!= null
) { l1
= l1
. next
; } if ( l2
!= null
) { l2
= l2
. next
; } } if ( carry
> 0 ) { tail
. next
= new ListNode ( 1 ) ; } return head
; }
}
3. 無重復(fù)字符的最長子串
關(guān)鍵點(滑動窗口):
右窗口臨近元素的加入條件:!occ.contains(s.charAt(rk + 1)) 左窗口移除元素的邏輯:剛好不包含rk+1處的重復(fù)元素
class Solution { public int lengthOfLongestSubstring ( String s
) { Set
< Character> occ
= new HashSet < Character> ( ) ; int n
= s
. length ( ) ; int rk
= - 1 , ans
= 0 ; for ( int i
= 0 ; i
< n
; ++ i
) { if ( i
!= 0 ) { occ
. remove ( s
. charAt ( i
- 1 ) ) ; } while ( rk
+ 1 < n
&& ! occ
. contains ( s
. charAt ( rk
+ 1 ) ) ) { occ
. add ( s
. charAt ( rk
+ 1 ) ) ; ++ rk
; } ans
= Math
. max ( ans
, rk
- i
+ 1 ) ; } return ans
; }
}
5. 最長回文子串
關(guān)鍵點(動態(tài)規(guī)劃):
dp的填表方向:列自左往右,行自上往下 獲取更大的回文子串判斷條件:j - i + 1 > ans.length()
class Solution { public static String
longestPalindrome ( String s
) { if ( s
. length ( ) <= 1 ) return s
; boolean [ ] [ ] dp
= new boolean [ s
. length ( ) ] [ s
. length ( ) ] ; String ans
= "" ; for ( int i
= 0 ; i
< s
. length ( ) ; ++ i
) { dp
[ i
] [ i
] = true ; } ans
= s
. substring ( 1 , 2 ) ; for ( int j
= 1 ; j
< s
. length ( ) ; ++ j
) { for ( int i
= 0 ; i
< j
; ++ i
) { if ( j
== i
+ 1 ) { dp
[ i
] [ j
] = s
. charAt ( i
) == s
. charAt ( j
) ; } else { dp
[ i
] [ j
] = ( s
. charAt ( i
) == s
. charAt ( j
) && dp
[ i
+ 1 ] [ j
- 1 ] ) ; } if ( dp
[ i
] [ j
] && j
- i
+ 1 > ans
. length ( ) ) { ans
= s
. substring ( i
, j
+ 1 ) ; } } } return ans
; }
}
6. Z 字形變換
關(guān)鍵點:找規(guī)律( 詳情見 Z字形變換(LeetCode第6題))
class Solution {
public : string
convert ( string s
, int numRows
) { if ( numRows
== 1 ) return s
; string
ans ( "" ) ; int down
= 2 * numRows
- 4 , up
= 2 ; for ( int i
= 0 ; i
< numRows
; i
++ ) { int k
= i
, flag
= 1 ; if ( i
== 0 || i
== numRows
- 1 ) { while ( k
< s
. size ( ) ) { ans
+ = s
[ k
] ; k
= k
+ 2 * numRows
- 2 ; } continue ; } else while ( k
< s
. size ( ) ) { ans
+ = s
[ k
] ; flag
++ % 2 == 1 ? k
= k
+ down
: k
= k
+ up
; } down
- = 2 ; up
+ = 2 ; } return ans
; }
} ;
8. 字符串轉(zhuǎn)換整數(shù) (atoi)
方法:有限狀態(tài)機(不是很會,抄的題解,知道有這回事)
class Solution { public int myAtoi ( String str
) { Automaton automaton
= new Automaton ( ) ; int length
= str
. length ( ) ; for ( int i
= 0 ; i
< length
; ++ i
) { automaton
. get ( str
. charAt ( i
) ) ; } return ( int ) ( automaton
. sign
* automaton
. ans
) ; }
} class Automaton { public int sign
= 1 ; public long ans
= 0 ; private String state
= "start" ; private Map
< String
, String
[ ] > table
= new HashMap < String
, String
[ ] > ( ) { { put ( "start" , new String [ ] { "start" , "signed" , "in_number" , "end" } ) ; put ( "signed" , new String [ ] { "end" , "end" , "in_number" , "end" } ) ; put ( "in_number" , new String [ ] { "end" , "end" , "in_number" , "end" } ) ; put ( "end" , new String [ ] { "end" , "end" , "end" , "end" } ) ; } } ; public void get ( char c
) { state
= table
. get ( state
) [ get_col ( c
) ] ; if ( "in_number" . equals ( state
) ) { ans
= ans
* 10 + c
- '0' ; ans
= sign
== 1 ? Math
. min ( ans
, ( long ) Integer
. MAX_VALUE
) : Math
. min ( ans
, - ( long ) Integer
. MIN_VALUE
) ; } else if ( "signed" . equals ( state
) ) { sign
= c
== '+' ? 1 : - 1 ; } } private int get_col ( char c
) { if ( c
== ' ' ) { return 0 ; } if ( c
== '+' || c
== '-' ) { return 1 ; } if ( Character
. isDigit ( c
) ) { return 2 ; } return 3 ; }
}
17. 電話號碼的字母組合
關(guān)鍵點(dfs+狀態(tài)重置):
Map、StringBuffer類型的使用 當(dāng)dfs層數(shù)到達號碼串長時,剪枝
class Solution { public List
< String> letterCombinations ( String digits
) { List
< String> answers
= new ArrayList < String> ( ) ; if ( digits
. length ( ) == 0 ) { return answers
; } Map
< Character, String> phoneMap
= new HashMap < Character, String> ( ) { { put ( '2' , "abc" ) ; put ( '3' , "def" ) ; put ( '4' , "ghi" ) ; put ( '5' , "jkl" ) ; put ( '6' , "mno" ) ; put ( '7' , "pqrs" ) ; put ( '8' , "tuv" ) ; put ( '9' , "wxyz" ) ; } } ; dfs ( answers
, phoneMap
, digits
, 0 , new StringBuffer ( ) ) ; return answers
; } public void dfs ( List
< String> answers
, Map
< Character, String> phoneMap
, String digits
, int deepth
, StringBuffer path
) { if ( deepth
== digits
. length ( ) ) { answers
. add ( path
. toString ( ) ) ; } else { char digit
= digits
. charAt ( deepth
) ; String letters
= phoneMap
. get ( digit
) ; for ( int i
= 0 ; i
< letters
. length ( ) ; i
++ ) { path
. append ( letters
. charAt ( i
) ) ; dfs ( answers
, phoneMap
, digits
, deepth
+ 1 , path
) ; path
. deleteCharAt ( deepth
) ; } } }
}
46. 全排列
關(guān)鍵點(dfs):狀態(tài)變量,狀態(tài)重置,以棧的形式使用Deque(java)
class Solution { public List
< List
< Integer> > permute ( int [ ] nums
) { List
< List
< Integer> > res
= new ArrayList < > ( ) ; if ( nums
. length
== 0 ) { return res
; } Deque
< Integer> path
= new ArrayDeque < > ( ) ; boolean [ ] used
= new boolean [ nums
. length
] ; int deepth
= 0 ; dfs ( nums
, res
, path
, used
, deepth
) ; return res
; } private void dfs ( int [ ] nums
, List
< List
< Integer> > res
, Deque
< Integer> path
, boolean [ ] used
, int deepth
) { if ( deepth
== nums
. length
) { res
. add ( new ArrayList < > ( path
) ) ; return ; } for ( int i
= 0 ; i
< nums
. length
; ++ i
) { if ( used
[ i
] == true ) { continue ; } path
. addLast ( nums
[ i
] ) ; used
[ i
] = true ; dfs ( nums
, res
, path
, used
, deepth
+ 1 ) ; path
. removeLast ( ) ; used
[ i
] = false ; } }
}
62. 不同路徑
關(guān)鍵點(動態(tài)規(guī)劃):
先填首行與首列 再依次列從左往右,行從上往下填表
class Solution { public int uniquePaths ( int m
, int n
) { int [ ] [ ] dp
= new int [ m
] [ n
] ; for ( int i
= 0 ; i
< m
; ++ i
) { dp
[ i
] [ 0 ] = 1 ; } for ( int i
= 0 ; i
< n
; ++ i
) { dp
[ 0 ] [ i
] = 1 ; } for ( int i
= 1 ; i
< m
; ++ i
) { for ( int j
= 1 ; j
< n
; ++ j
) { dp
[ i
] [ j
] = dp
[ i
- 1 ] [ j
] + dp
[ i
] [ j
- 1 ] ; } } return dp
[ m
- 1 ] [ n
- 1 ] ; }
}
73. 矩陣置零
關(guān)鍵點:行列標(biāo)記數(shù)組,先標(biāo)記再替換
class Solution { public void setZeroes ( int [ ] [ ] matrix
) { int m
= matrix
. length
, n
= matrix
[ 0 ] . length
; boolean [ ] row
= new boolean [ m
] ; boolean [ ] col
= new boolean [ n
] ; for ( int i
= 0 ; i
< m
; i
++ ) { for ( int j
= 0 ; j
< n
; j
++ ) { if ( matrix
[ i
] [ j
] == 0 ) { row
[ i
] = col
[ j
] = true ; } } } for ( int i
= 0 ; i
< m
; i
++ ) { for ( int j
= 0 ; j
< n
; j
++ ) { if ( row
[ i
] || col
[ j
] ) { matrix
[ i
] [ j
] = 0 ; } } } }
}
94. 二叉樹的中序遍歷
(數(shù)據(jù)結(jié)構(gòu)基礎(chǔ))
class Solution { public List
< Integer> inorderTraversal ( TreeNode root
) { List
< Integer> answer
= new ArrayList ( ) ; if ( root
== null
) return answer
; PT ( answer
, root
) ; return answer
; } public void PT ( List
< Integer> answer
, TreeNode root
) { if ( root
. left
!= null
) PT ( answer
, root
. left
) ; answer
. add ( root
. val
) ; if ( root
. right
!= null
) PT ( answer
, root
. right
) ;
}
}
130. 被圍繞的區(qū)域
關(guān)鍵點(dfs):
從上下左右四個方向深度優(yōu)先搜索邊界的O以及與其相連的O,并替換成‘#’ 填充所有未被搜索到的O(被圍繞的O),再將#還原為O(邊界O)
class Solution { public void solve ( char [ ] [ ] board
) { if ( board
== null
|| board
. length
== 0 ) return ; int m
= board
. length
; int n
= board
[ 0 ] . length
; for ( int i
= 0 ; i
< m
; i
++ ) { for ( int j
= 0 ; j
< n
; j
++ ) { boolean isEdge
= i
== 0 || j
== 0 || i
== m
- 1 || j
== n
- 1 ; if ( isEdge
&& board
[ i
] [ j
] == 'O' ) { dfs ( board
, i
, j
) ; } } } for ( int i
= 0 ; i
< m
; i
++ ) { for ( int j
= 0 ; j
< n
; j
++ ) { if ( board
[ i
] [ j
] == 'O' ) { board
[ i
] [ j
] = 'X' ; } if ( board
[ i
] [ j
] == '#' ) { board
[ i
] [ j
] = 'O' ; } } } } public void dfs ( char [ ] [ ] board
, int i
, int j
) { if ( i
< 0 || j
< 0 || i
>= board
. length
|| j
>= board
[ 0 ] . length
|| board
[ i
] [ j
] == 'X' || board
[ i
] [ j
] == '#' ) { return ; } board
[ i
] [ j
] = '#' ; dfs ( board
, i
- 1 , j
) ; dfs ( board
, i
+ 1 , j
) ; dfs ( board
, i
, j
- 1 ) ; dfs ( board
, i
, j
+ 1 ) ; }
}
144. 二叉樹的前序遍歷
(數(shù)據(jù)結(jié)構(gòu)基礎(chǔ))
class Solution { public List
< Integer> preorderTraversal ( TreeNode root
) { List
< Integer> answer
= new ArrayList ( ) ; if ( root
== null
) return answer
; PT ( answer
, root
) ; return answer
; } public void PT ( List
< Integer> answer
, TreeNode root
) { answer
. add ( root
. val
) ; if ( root
. left
!= null
) PT ( answer
, root
. left
) ; if ( root
. right
!= null
) PT ( answer
, root
. right
) ; }
}
145. 二叉樹的后序遍歷
(數(shù)據(jù)結(jié)構(gòu)基礎(chǔ))
class Solution { public List
< Integer> postorderTraversal ( TreeNode root
) { List
< Integer> answer
= new ArrayList ( ) ; if ( root
== null
) return answer
; PT ( answer
, root
) ; return answer
; } public void PT ( List
< Integer> answer
, TreeNode root
) { if ( root
. left
!= null
) PT ( answer
, root
. left
) ; if ( root
. right
!= null
) PT ( answer
, root
. right
) ; answer
. add ( root
. val
) ; }
}
198. 打家劫舍
關(guān)鍵點(動態(tài)規(guī)劃):
狀態(tài)轉(zhuǎn)移方程:dp[i]=max(dp[i?2]+nums[i],dp[i?1]) 邊界條件:dp[0]=nums[0],dp[1]=max(nums[0],nums[1]) ?
class Solution { public int rob ( int [ ] nums
) { if ( nums
. length
== 0 ) return 0 ; if ( nums
. length
== 1 ) return nums
[ 0 ] ; if ( nums
. length
== 2 ) return Math
. max ( nums
[ 0 ] , nums
[ 1 ] ) ; int [ ] dp
= new int [ nums
. length
] ; dp
[ 0 ] = nums
[ 0 ] ; dp
[ 1 ] = Math
. max ( nums
[ 0 ] , nums
[ 1 ] ) ; for ( int i
= 2 ; i
< nums
. length
; ++ i
) { dp
[ i
] = Math
. max ( dp
[ i
- 2 ] + nums
[ i
] , dp
[ i
- 1 ] ) ; } return dp
[ nums
. length
- 1 ] ; }
}
?
200. 島嶼數(shù)量
思路:
遍歷二維數(shù)組,遇到1,島嶼數(shù)量+1 DFS將與其連起來的1替換成0,退出DFS繼續(xù)遍歷二維數(shù)組
class Solution { public int numIslands ( char [ ] [ ] grid
) { int num_Islands
= 0 ; for ( int i
= 0 ; i
< grid
. length
; ++ i
) { for ( int j
= 0 ; j
< grid
[ 0 ] . length
; ++ j
) { if ( grid
[ i
] [ j
] == '1' ) { ++ num_Islands
; dfs ( grid
, i
, j
) ; } } } return num_Islands
; } public void dfs ( char [ ] [ ] grid
, int i
, int j
) { if ( i
< 0 || j
< 0 || i
> grid
. length
- 1 || j
> grid
[ 0 ] . length
- 1 || grid
[ i
] [ j
] == '0' ) { return ; } grid
[ i
] [ j
] = '0' ; dfs ( grid
, i
- 1 , j
) ; dfs ( grid
, i
+ 1 , j
) ; dfs ( grid
, i
, j
- 1 ) ; dfs ( grid
, i
, j
+ 1 ) ; }
}
445. 兩數(shù)相加 II
關(guān)鍵點(棧):
保證位數(shù)對齊:將兩個數(shù)的每個位數(shù)都分別入棧,然后從兩個棧頂開始相加
class Solution { public ListNode
addTwoNumbers ( ListNode l1
, ListNode l2
) { Deque
< Integer> s1
= new ArrayDeque < > ( ) ; while ( l1
!= null
) { s1
. addLast ( l1
. val
) ; l1
= l1
. next
; } Deque
< Integer> s2
= new ArrayDeque < > ( ) ; while ( l2
!= null
) { s2
. addLast ( l2
. val
) ; l2
= l2
. next
; } ListNode answer
= new ListNode ( 0 ) ; int carry
= 0 ; while ( ! s1
. isEmpty ( ) || ! s2
. isEmpty ( ) ) { int sum
= ( s1
. isEmpty ( ) ? 0 : s1
. removeLast ( ) ) + ( s2
. isEmpty ( ) ? 0 : s2
. removeLast ( ) ) + carry
; ListNode newnode
= new ListNode ( sum
% 10 ) ; newnode
. next
= answer
. next
; answer
. next
= newnode
; if ( sum
>= 10 ) { carry
= sum
/ 10 ; } else { carry
= 0 ; } } if ( carry
!= 0 ) { ListNode newnode
= new ListNode ( 1 ) ; newnode
. next
= answer
. next
; answer
. next
= newnode
; } return answer
. next
; }
}
486. 預(yù)測贏家
關(guān)鍵點(動態(tài)規(guī)劃):
先設(shè)計暴力解法,再用dp數(shù)組記錄重復(fù)運算進行優(yōu)化
class Solution { public boolean PredictTheWinner ( int [ ] nums
) { int [ ] [ ] dp
= new int [ nums
. length
] [ nums
. length
] ; for ( int i
= 0 ; i
< nums
. length
; ++ i
) { dp
[ i
] [ i
] = nums
[ i
] ; } for ( int i
= nums
. length
- 2 ; i
>= 0 ; -- i
) { for ( int j
= i
+ 1 ; j
<= nums
. length
- 1 ; ++ j
) { dp
[ i
] [ j
] = Math
. max ( nums
[ i
] - dp
[ i
+ 1 ] [ j
] , nums
[ j
] - dp
[ i
] [ j
- 1 ] ) ; } } return dp
[ 0 ] [ nums
. length
- 1 ] >= 0 ; }
}
503. 下一個更大元素 II
(暴力,單調(diào)棧為更優(yōu)解)
class Solution { public int [ ] nextGreaterElements ( int [ ] nums
) { int [ ] ans
= new int [ nums
. length
] ; for ( int n
= 0 ; n
< nums
. length
; ++ n
) { int count
= 0 ; for ( int i
= ( n
+ 1 ) % nums
. length
; i
< nums
. length
; i
= ( i
+ 1 ) % nums
. length
) { if ( ++ count
>= nums
. length
) { ans
[ n
] = - 1 ; break ; } if ( nums
[ n
] < nums
[ i
] ) { ans
[ n
] = nums
[ i
] ; break ; } } } return ans
; }
}
567. 字符串的排列
關(guān)鍵點(滑動窗口):
用長度為26的一維數(shù)組維護一個滑動窗口 窗口在l2滑動的過程,只要滿足窗口內(nèi)各字母數(shù)量與l1內(nèi)各字母數(shù)相符,即匹配成功
class Solution { public boolean checkInclusion ( String s1
, String s2
) { if ( s1
. length ( ) > s2
. length ( ) ) return false ; int [ ] s1map
= new int [ 26 ] ; int [ ] s2map
= new int [ 26 ] ; for ( int i
= 0 ; i
< s1
. length ( ) ; i
++ ) { s1map
[ s1
. charAt ( i
) - 'a' ] ++ ; s2map
[ s2
. charAt ( i
) - 'a' ] ++ ; } for ( int i
= 0 ; i
< s2
. length ( ) - s1
. length ( ) ; i
++ ) { if ( isMatch ( s1map
, s2map
) ) { return true ; } s2map
[ s2
. charAt ( i
+ s1
. length ( ) ) - 'a' ] ++ ; s2map
[ s2
. charAt ( i
) - 'a' ] -- ; } return isMatch ( s1map
, s2map
) ; } private static boolean isMatch ( int [ ] charArray1
, int [ ] charArray2
) { for ( int i
= 0 ; i
< charArray1
. length
; i
++ ) { if ( charArray1
[ i
] != charArray2
[ i
] ) { return false ; } } return true ; }
}
877. 石子游戲
(預(yù)測贏家的同類題,此處可用數(shù)學(xué)解,略)
class Solution { public boolean stoneGame ( int [ ] piles
) { return true ; }
}
總結(jié)
???????認識了很多算法,像動態(tài)規(guī)劃、滑動窗口、Dfs、回溯、雙指針…認識了很多數(shù)據(jù)結(jié)構(gòu),像Java的Set、Deque、ArrayList、LinkedList…
???????我身邊有很多人,參加過很多競賽,獲得過很多榮譽。有人問過我說:他們各方面都比你優(yōu)秀,努力程度也不比你差,為啥還要努力?我說,有意義的是過程,結(jié)果是大家都看得到的,只有過程是真正屬于自己的,即使未來不青睞我,我也要繼續(xù),因為:
???????“強大者應(yīng)持謙卑之心不可因力量而跋扈, ???????????????弱小者應(yīng)持上進之心不可因不敵而麻木。”
繼續(xù)打題、繼續(xù)前進… (未完待續(xù))
總結(jié)
以上是生活随笔 為你收集整理的力扣(简单+中等)50题整理总结 的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔 網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔 推薦給好友。