算法刷題收穫
序言
先達到算法的廣度,有了一定的算法積累,纔會有自己的一些想法和見解,在認識上和解題思路上纔會idea如泉湧,纔會有一定的深度。多看(看題,看題解,看視頻題解)多練(將算法的代碼多手寫幾遍)
java API調用
string常用api
String str="abc";
/**
* "a.b.cd".split("\\.") 按照.將字符串切割成字符串數組["a","b","cd"]
* str.startsWith("a") 該字符串是否以a開頭
* str.indexOf('a') 首次a字符所在的下標
* str.charAt('0') 獲得指定下標的字符
* str.replace('a','q') 把a換成q,想替換所有可以用replaceAll();
* str.substring(0,2) 截取下標0~1的字串
* str.contains("ab") 是否包含字串ab
* str.concat("abc") 拼接字符串
* str.equalsIgnoreCase("ABC") 字符串相等?忽略大小寫
* str.toUpperCase() 將字母小寫全部轉爲大寫
* str.codePointAt(0) 返回指定下標對應字符的10進制的值
*/
Arrays常用api
int[] nums=new int[]{1,2,3,4,5};
/**
* 常用api
*/
int[] ints = Arrays.copyOfRange(nums, 0, 2); //[1,2] //nums數組類型只能是基本類型
List<Integer> list = Arrays.asList(nums); //nums數組類型只能是包裝類型
List<Integer> list1 = Arrays.asList(1, 2, 3);//將數組轉爲List,不過數組類型必須是包裝類型
int index = Arrays.binarySearch(nums, 4); //返回匹配到元素的下標
Integer[] objects =(Integer[]) list.toArray() ; //list轉數組
Stream<Integer> stream = Arrays.stream((Integer[]) list.toArray()); // list轉stream流
優先隊列【PriorityQueue】,優先hash【TreeMap】
public static void main(String[] args) {
TreeMap treeMap = new TreeMap<Integer,Integer>();
treeMap.put(10,10);treeMap.put(1,1);treeMap.put(3,3);
treeMap.get(treeMap.firstKey()); //獲得值最小的key的value[結果是:1]
PriorityQueue<Integer>priorityQueue=new PriorityQueue<>();
priorityQueue.add(10);priorityQueue.add(1);priorityQueue.add(3);
System.out.println(priorityQueue.poll());//優先隊列,本質就是小頂堆,彈出隊頭元素【結果是1】
PriorityQueue<Integer>priorityQueue1=new PriorityQueue<>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
}); //構造大頂堆【優先隊列】---自定義排序規則
}
- 去重重複的數組
// 建立去重的容器
Set<List<Integer>> result_set = new TreeSet<>(new Comparator<List<Integer>>() {
@Override
public int compare(List<Integer> o1, List<Integer> o2) {
//Arrays.sort(o1);Arrays.sort(o2);
for (int i = 0; i < o1.size(); i++) {
if (!o1.get(i).equals(o2.get(i))) return o1.get(i) - o2.get(i);
}
return 0;
}
});
[[1,2,3],[3,2,1],[1,1,1],[2,3,1]]
將元素相同的數組進行“去重”
A.containsAll(B) // A【1,2,3】集合是否全部包含者B【2,2,2】的元素-----true,它並不能解決上述問題
hashmap巧解題
位運算
&,|,~,^,>>,<<,>>>
java移位運算符<< 和 >> 和 >>>
dim-原碼反碼補碼及加減運算
假設在8位的計算機上,整數數據類型佔8位,數分爲有符號【1位是符號位(0正1負),7位是數值位】和無符號數【8位都是數值位,即表示正整數】對於移位運算,先將數表示成8位的二進制的形式.左邊是高位,右邊是低位
" <<" 表示左移,不分正負數,低位補0;
" >>" 表示右移,如果該數爲正,則高位補0,若爲負數,則高位補1;
">>>"表示無符號右移,也叫邏輯右移,即若該數爲正,則高位補0,而若該數爲負數,則右移後高位同樣補0
r = 20 << 2=80 【左移2位,即擴大2^2倍】
r = -20 << 2=-80 【對負數是絕對值擴大了】
r=20>>>1 =10【右移一位,即縮小了2倍】
一個數爲n【n可能很大】
n&1 結果:0或1,【巧用 n&(n−1)求二進制中1的個數】
~做數的調整用的
^遞歸運算裏面常用(不進位的二進制加法)
|待補充
例題:第K個語法符號
class Solution {
public int kthGrammar(int N, int K) {
if (N == 1) return 0;
return (~K & 1) ^ kthGrammar(N-1, (K+1)/2);
}
}
數字
純數學運算
%取餘,/除法,int carry進位
- 迴文數:判斷一個整數是否是迴文數
public boolean isPalindrome(int x) {
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false;
}
int a = 0;
while (x > a) {
a = a * 10 + x % 10;
x = x / 10;
}
return x == a || x == a / 10;
}
數字字符轉換
字符和數字根據ASCII碼錶可以進行相互轉換【數字可以當作字符來使用,字符也可以當作數字來使用】
char num=65; //num='A'
int num='0'; //num=48
int num='9'-'0'; //num=9
進制相加【整數/小數類型的字符串相加】
public class Solution {
public static void main(String[] args) {
addIncludeFloat("1.88", "2.88");
}
/**
* 進制相加
*/
static String numberSystemConversion(String s1, String s2) {
int i = s1.length() - 1;
int j = s2.length() - 1;
int carry = 0;
StringBuilder res = new StringBuilder();
while (i >= 0 || j >= 0 || carry != 0) {
if (i >= 0) carry += (s1.charAt(i--) - '0');
if (j >= 0) carry += (s2.charAt(j--) - '0');
res.append(carry % 9);
carry = carry / 9;
}
return res.reverse().toString();
}
/**
* 整數/小數類型的字符串相加
*/
static void addIncludeFloat(String s1, String s2) {
int index1 = s1.indexOf('.');
int index2 = s2.indexOf('.');
String int1 = s1.substring(0, index1);
String int2 = s2.substring(0, index2);
String float1 = s1.substring(index1 + 1, s1.length());
String float2 = s2.substring(index2 + 1, s2.length());
StringBuilder res = new StringBuilder();
String intSum = numberSystemConversion(int1, int2);
String flrSum = numberSystemConversion(float1, float2);
if (flrSum.length() > Math.max(float1.length(), float2.length())) {
res.append(numberSystemConversion(intSum, "1") + "." + flrSum.substring(1));
} else {
res.append(intSum + "." + flrSum);
}
System.out.println(res);
}
}
整數反轉
整數轉字符,string轉StringBuilder,字符轉整數
public void reverse() {
int x = -120;
String numStr = x + ""; //整數轉字符
StringBuilder numStrOpt = new StringBuilder(numStr); //string轉StringBuilder
String res = numStrOpt.reverse().toString();
if (res.charAt(0) == '0') res = res.substring(1);
if (res.charAt(res.length() - 1) == '-') res = "-" + res.substring(0, res.length() - 1);
//字符轉整數try(){Integer.parseInt(res);}
System.out.println(res);
}
完全平方數
https://leetcode-cn.com/problems/perfect-squares/
醜數
字符串
正則表達式
[email protected]
[email protected]
[email protected]
//String regex = "\\w+@\\w+\\.[a-z]+(\\.[a-z]+)?"; 匹配郵箱的正則表達式
Pattern.matches(".*\\d", "abc2"); //結果爲:true 解釋:.*可以匹配任何字符串,它相當於(.)*
Pattern.matches("\\d+","2223aa");//字符串能否匹配 結果: false
System.out.println(Pattern.matches("\\d+[a-zA-Z]+","2223aa")); //結果: true
Pattern pattern = Pattern.compile("\\d+");
Matcher matcher = pattern.matcher("aa23ett55");
/**
* matcher
* .start()返回匹配到的子字符串在字符串中的索引位置.
* .end()返回匹配到的子字符串的最後一個字符在字符串中的索引位置.
* .group()返回匹配到的子字符串【要先進行matcher.find()判斷操作】
*/
if(matcher.find()) System.out.print(matcher.group()); //23
while(matcher.find()) System.out.print(matcher.group()+"\t");//查找並獲取匹配到的內容 結果:23 55
String[] str=pattern.split("電話:0514郵箱:[email protected]");//按模式切割數組 結果:["電話:","郵箱:[email protected]"]
字符串轉換整數
使用正則
public int myAtoi(String str) {
/**
* " -42" 輸出: -42
* "4193 with words" 輸出: 4193
* "words and 987" 輸出: 0
* "-91283472332" 輸出: -2147483648 【整數溢出】
*/
String regex = "^\\s*([-+]?\\d+){1}";
Matcher matcher = Pattern.compile(regex).matcher(str);
if (matcher.find()){
String group = matcher.group().trim();
try {
return Integer.parseInt(group);
}catch (Exception e){
if(group.contains("-")){
return Integer.MIN_VALUE;
}else return Integer.MAX_VALUE;
}
}else {
return 0;
}
}
使用確定自動機
【判斷字符是否是數字Character.isDigit(’ '),字符串轉整數溢出的情況可以用long長整型變量來解決這一問題,long ans > 1L + Integer.MAX_VALUE】
origin link
public int myAtoi1(String str) {
str = str.trim();
if (str.length() == 0) return 0;
if (!Character.isDigit(str.charAt(0))
&& str.charAt(0) != '-' && str.charAt(0) != '+')
return 0;
long ans = 0L;
boolean neg = str.charAt(0) == '-';
int i = !Character.isDigit(str.charAt(0)) ? 1 : 0;
while (i < str.length() && Character.isDigit(str.charAt(i))) {
ans = ans * 10 + (str.charAt(i++) - '0');
if (!neg && ans > Integer.MAX_VALUE) { // 2147483647
ans = Integer.MAX_VALUE;
break;
}
if (neg && ans > 1L + Integer.MAX_VALUE) { // -2147483648
ans = 1L + Integer.MAX_VALUE;
break;
}
}
return neg ? (int) -ans : (int) ans;
}
正則表達式匹配【dp/回溯】
- 有 * 【首字符匹配(*匹配多個)||首字符不匹配(*匹配0個)】,無 *【首字符匹配&&後續都要匹配】
- 程序終結的條件:【模式串爲空,匹配串不爲空,結果:fasle】,【模式串爲空,匹配串爲空,結果:true】
- 不斷縮小字符串,重複執行以上步驟。
public boolean isMatch(String s, String p){
if (p.isEmpty()) return s.isEmpty();
boolean firstMatch=(!s.isEmpty()&&(s.charAt(0)==p.charAt(0)||p.charAt(0)=='.'));
if (p.length()>1&&p.charAt(1)=='*'){
return (firstMatch&&isMatch(s.substring(1),p))||isMatch(s,p.substring(2));
}else {
return firstMatch&&isMatch(s.substring(1),p.substring(1));
}
}
遞歸
階乘【普通遞歸和尾遞歸的實現】
//一個函數中所有遞歸形式的調用都出現在函數的末尾,我們稱這個遞歸函數是尾遞歸的
//當遞歸調用是整個函數體中最後執行的語句且它的返回值不屬於表達式的一部分時,這個遞歸調用就是尾遞歸
/**
* 普通遞歸(這步計算需要依賴遞歸函數的返回結果)
*/
int Factorial(int n){
if (n==1) return 1;
else return n*Factorial(n-1); //尾遞歸的遞歸函數,但不是遞歸調用
}
/**
* 尾遞歸【Factorial_TailRecursion(4,1)】
* (這步計算不需要依賴遞歸函數的返回結果)
*/
int Factorial_TailRecursion(int n, int a)
{
if (n < 0)
return 0;
else if (n == 0)
return 1;
else if (n == 1)
return a;
else
return Factorial_TailRecursion(n - 1, n * a);
//它是尾遞歸的遞歸函數,並且也是遞歸調用的
// 【當編譯器檢測到一個函數調用是尾遞歸的時候,它就覆蓋當前的活動記錄而不是在棧中去創建一個新的,
// 這樣所使用的棧空間就大大縮減了,這使得實際的運行效率會變得更高。】
}
尋找兩個有序數組的中位數
orgin link
兩個排好序的數組。都中間分一下,總體的中位數肯定是在二分後4塊數據中的兩塊
[1,3,5,7],[2,4,6,8]
1的中位數是3,5
2的中位數是4,6
和起來[3,4,5,6]的中位數4,5就是兩個有序數組的中位數
二分查找:即夾逼法
輸出比賽匹配對
NBA比賽球隊對戰順序(限制輸入n是2的次方數)leedcode544.輸出比賽匹配對
由於n限定了是2的次方數,那麼就是可以一直對半分的,比如開始有n隊,第一拆分爲n/2對匹配,然後再對半拆,就是n/2/2,直到拆到n爲1停止,而且每次都是首與末配對,次首與次末配對
String findContestMatch(int n) {
List<String> v = new ArrayList<>();
for (int i = 1; i <= n; ++i) v.add(String.valueOf(i));
helper(n, v);
return v.get(0);
}
void helper(int n, List<String> v) {
if (n == 1) return;
for (int i = 0; i < n; ++i) {
v.set(i, "(" + v.get(i) + "," + v.get(n - i - 1)+ ")");
}
helper(n / 2, v);
}
698. 劃分爲k個相等的子集
https://leetcode-cn.com/problems/partition-to-k-equal-sum-subsets/
視頻講解
private boolean backtracking(int[] nums, int k, int target, int cur, int start, boolean[] used) {
// 返回條件
if (k == 0) return true;
if (cur == target) {
// 構建下一個集合
return backtracking(nums, k-1, target, 0, 0, used);
}
for (int i = start; i < nums.length; i++) {
if (!used[i] && cur+nums[i] <= target) {
used[i] = true;
if (backtracking(nums, k, target, cur+nums[i], i+1, used)) return true;
used[i] = false;
}
}
return false;
}
public boolean canPartitionKSubsets(int[] nums, int k) {
// 注意nums[i] > 0
int sum = 0, maxNum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
if (maxNum < nums[i]) maxNum = nums[i];
}
if (sum % k != 0 || maxNum > sum/k) return false;
boolean[] used = new boolean[nums.length];
return backtracking(nums, k, sum/k, 0, 0, used);
}
動態規劃
最長迴文子串
public void longestPalindrome() {
String s="babbad";
boolean[][] dp = new boolean[s.length()][s.length()];
int max = 0;
int left=0;
int right=0;
for (int i = 1; i < s.length(); i++) {
for (int j = 0; j < i; j++) {
dp[i][j] =( s.charAt(i) == s.charAt(j) && (i - j < 3 ||dp[i - 1][j + 1]));
if (dp[i][j]&&i - j > max){
max = i - j;
left=j;
right=i;
}
}
}
System.out.println(s.substring(left,right+1));
}
回溯
最大層內元素和
bfs實現
class Solution {
public int maxLevelSum(TreeNode root) {
//用TreeMap來實現 層內元素之和 最大 的那幾層中層號最小的那層的層號【比如2層,3層的和都是10,那麼返回2】
TreeMap<Integer, Integer> treeMap = new TreeMap<>(); //key:每層的和,value,所處的層
Queue<TreeNode>queue=new LinkedList<>();
queue.add(root);
int h=0;
while (!queue.isEmpty()) {
int len = queue.size();
int curSum=0;
for (int i = 0; i <len; i++) {
TreeNode curNode = queue.poll();
/**
*主要代碼就是
**/
if (curNode!=null) {
curSum += curNode.val;
if (curNode.left != null) queue.add(curNode.left);
if (curNode.right != null) queue.add(curNode.right);
}
}
++h;
if (!treeMap.containsKey(curSum)){treeMap.put(curSum,h);}
}
return treeMap.get(treeMap.lastKey());
}
}
dfs實現
class SolutionTest {
int n = 10000;
int[] levelSum = new int[n];
public void inorder(TreeNode node, int level) {
if (node != null) {
inorder(node.left, level + 1);
levelSum[level] += node.val; //解題的關鍵代碼
inorder(node.right, level + 1);
}
}
@Test
public void maxLevelSum() {
TreeNode root=new TreeNode(0).generate();
inorder(root, 1);
int maxIdx = 0;
for (int i = 0; i < n; ++i)
maxIdx = levelSum[i] > levelSum[maxIdx] ? i : maxIdx; //通過標記最大值的下標,實現一次遍歷找到最大值
System.out.println(maxIdx);
}
}
BFS和DFS的區別
對於結點的全遍歷,二者性能相當。
對於求最短路徑,BFS快,你想啊,BFS從起點開始一圈圈往外擴,但凡見到終點即結束遍歷,大概率不會把結點全遍歷完。但是對於DFS,必須每條路徑都走一遍,經過所有路徑長度比較後,纔敢確定最短的那條,所以,DFS一定要遍歷完所有結點,時間當然長了。
DFS)是一種用於遍歷或搜索樹或圖的算法。沿着樹的深度遍歷樹的節點,儘可能深的搜索樹的分支。當節點v的所在邊都己被探尋過,搜索將回溯到發現節點v的那條邊的起始節點。這一過程一直進行到已發現從源節點可達的所有節點爲止。如果還存在未被發現的節點,則選擇其中一個作爲源節點並重復以上過程,整個進程反覆進行直到所有節點都被訪問爲止。屬於盲目搜索。【可以進行剪支優化】
回溯算法實際上一個類似枚舉的搜索嘗試過程,主要是在搜索嘗試過程中尋找問題的解,當發現已不滿足求解條件時,就 “回溯” 返回,嘗試別的路徑。回溯法是一種選優搜索法,按選優條件向前搜索,以達到目標。但當探索到某一步時,發現原先選擇並不優或達不到目標,就退回一步重新選擇,這種走不通就退回再走的技術爲回溯法,而滿足回溯條件的某個狀態的點稱爲 “回溯點”。許多複雜的,規模較大的問題都可以使用回溯法,有“通用解題方法”的美稱。
回溯算法的基本思想是:從一條路往前走,能進則進,不能進則退回來,換一條路再試。
BFS例題:https://leetcode-cn.com/circle/article/oruvvf/
最大層內元素和【BFS和DFS都可以】
回溯法解數獨:https://leetcode-cn.com/circle/article/p24cTv/
BFS【解最短路徑類問題】
算法自始至終一直通過已找到和未找到頂點之間的邊界向外擴展,就是說,算法首先搜索和s距離爲k的所有頂點,然後再去搜索和S距離爲k+l的其他頂點。
爲了保持搜索的軌跡,寬度優先搜索爲每個頂點着色:白色、灰色或黑色。算法開始前所有頂點都是白色,隨着搜索的進行,各頂點會逐漸變成灰色,然後成爲黑色。在搜索中第一次碰到一頂點時,我們說該頂點被發現,此時該頂點變爲非白色頂點。因此,灰色和黑色頂點都已被發現,但是,寬度優先搜索算法對它們加以區分以保證搜索以寬度優先的方式執行。若(u,v)∈E且頂點u爲黑色,那麼頂點v要麼是灰色,要麼是黑色,就是說,所有和黑色頂點鄰接的頂點都已被發現。灰色頂點可以與一些白色頂點相鄰接,它們代表着已找到和未找到頂點之間的邊界。
用隊列去實現,不需要遞歸
BFS在求解最短路徑或者最短步數上有很多的應用
闖迷宮
在一個nn的矩陣裏走,從原點(0,0)開始走到終點(n-1,n-1),只能上下左右4個方向走,只能在給定的矩陣裏走,求最短步數。nn是01矩陣,0代表該格子沒有障礙,爲1表示有障礙物。
int mazeArr[maxn][maxn]; //表示的是01矩陣
int stepArr[4][2] = {{-1,0},{1,0},{0,-1},{0,1}}; //表示上下左右4個方向
int visit[maxn][maxn]; //表示該點是否被訪問過,防止回溯,回溯很耗時。
public class Test {
public static void main(String[] args) {
System.out.println(bfs(4));
}
static int mazeArr[][] = new int[][]{{0, 0, 1, 0}, {0, 0, 1, 0}, {0, 0, 0, 0}, {1, 0, 0, 0}}; //表示的是01矩陣(4,4)
static int[][] stepArr = new int[][]{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; //表示左右上下4個方向 ,(4,2)的二維數組【一個節點左右上下都嘗試走一遍後將其加入到隊尾,再從隊列彈出下一個節點】
static int[][] visit = new int[4][4]; //表示該點是否被訪問過,防止回溯,回溯很耗時。
private static int bfs(int n) {
Node node = new Node(0, 0, 0);
Queue<Node> queue = new LinkedList<Node>();
queue.add(node);
while (!queue.isEmpty()) {
Node newNode = queue.poll();
visit[newNode.x][newNode.y] = 1;
for (int i = 0; i < 4; i++) {
int x = newNode.x + stepArr[i][0];
int y = newNode.y + stepArr[i][1];
if (x == n - 1 && y == n - 1) {
return newNode.step + 1;
}
if (x >= 0 && y >= 0 && x < n && y < n
&& visit[x][y] == 0 && mazeArr[x][y] == 0) {
Node next = new Node(x, y, newNode.step + 1);
queue.add(next);
}
}
}
return -1;
}
private static class Node {
private int x;
private int y;
private int step;
public Node(int x, int y, int step) {
super();
this.x = x;
this.y = y;
this.step = step;
}
}
}
完全平方數
public int numSquares(int n) {
//1. 初始化三元素
//隊列:先入先出的容器;
Queue<Integer> queue=new LinkedList<>();
//已訪問集合:爲了避免隊列中插入重複的值
HashSet<Integer> visited=new HashSet<>(); //【創建 set 來存放非重複的元素】
//節點:最好寫成單獨的類,比如本例寫成 (value,step) 元組。也可寫成 (value,visited),看自己喜好和題目;
int count=0; //【定義 count 記錄完全平方數的個數】
queue.offer(n); //在容量已滿的情況下,add() 方法會拋出IllegalStateException異常,offer() 方法只會返回 false
visited.add(n);
while(!queue.isEmpty()){
count++; // 【每次有元素入隊就代表還有剩餘子平方數】
int len=queue.size(); //當層次遍歷第二層是先記錄下第一層的個數3【先固定下來】
for(int i=0;i<len;i++){ //不能寫成i<queue.size();
//2. 操作隊列 —— 彈出隊首節點:
int curNode=queue.poll();//【1{1,4,9},4{1,4,9},9{1,4,9}】外層的1,4,9是在隊列裏面的。該層循環不能省略
//3. 操作彈出的節點 —— 根據業務生成子節點(一個或多個):
for(int j=1;j*j<=curNode;j++){ // 【從 1 開始取,每次拿平方數來比較】
int nextNode=curNode-j*j; // 【用當前結點減去平方數 1,4,9...】
//4. 判斷這些節點 —— 符合業務條件,則return,
if(nextNode==0) // 【找完所有的平方數即可返回】
return count;
//不符合業務條件,且不在已訪問集合,則追加到隊尾,並加入已訪問集合:
if(!visited.contains(nextNode)) { // 【如果 set 裏面沒有存放當前元素,則可以入隊,入 set】
queue.offer(nextNode);
visited.add(nextNode);
}
}
}
}
//5. 若以上遍歷完成仍未return,那就返回未找到代碼(0):
return 0;
}
DFS
可以用棧實現,也可以用遞歸實現
leedcode例題
class Solution {
List<String>res=new ArrayList<>();
Map<Character,String>map= new HashMap<>();
void dfs(String digits,StringBuilder sb,int h){
if (sb.toString().length()==h) {res.add(sb.toString());return;}
if (digits.isEmpty()) return;
String s = map.get(digits.charAt(0));
for (int j = 0; j < s.length(); j++) {
sb.append(s.charAt(j));
dfs(digits.substring(1),sb,h);
sb.deleteCharAt(sb.length()-1);
}
}
public List<String> letterCombinations(String digits) {
if(digits.isEmpty()) return res;
map.put('2',"abc");map.put('3',"def");map.put('4',"ghi");map.put('5',"jkl");map.put('6',"mno");map.put('7',"pqrs");map.put('8',"tuv");map.put('9',"wxyz");
dfs(digits,new StringBuilder(),digits.length());
return res;
}
}
代碼主要還是參考排列組合中的回溯法的實現的代碼
public int maxLevelSum(TreeNode root) {
//用TreeMap來實現 層內元素之和 最大 的那幾層中層號最小的那層的層號【比如2層,3層的和都是10,那麼返回2】
TreeMap<Integer, Integer> treeMap = new TreeMap<>(); //key:每層的和,value,所處的層
Queue<TreeNode>queue=new LinkedList<>();
queue.add(root);
int h=0;
while (!queue.isEmpty()) {
int len = queue.size();
int curSum=0;
for (int i = 0; i <len; i++) {
TreeNode curNode = queue.poll();
/**
*主要代碼就是
**/
if (curNode!=null) {
curSum += curNode.val;
if (curNode.left != null) queue.add(curNode.left);
if (curNode.right != null) queue.add(curNode.right);
}
}
++h;
if (!treeMap.containsKey(curSum)){treeMap.put(curSum,h);}
}
return treeMap.get(treeMap.lastKey());
}
四數之和【leedcode超時了】
public List<List<Integer>> fourSum(int[] nums, int target) {
if(nums.length==0) return new ArrayList<>();
Arrays.sort(nums);
dfs(nums,new ArrayList<>(),4,0,target);
List<List<Integer>>s=new ArrayList<>(result_set);
return s;
}
// 建立去重的容器
Set<List<Integer>> result_set = new TreeSet<>(new Comparator<List<Integer>>() {
@Override
public int compare(List<Integer> o1, List<Integer> o2) {
for (int i = 0; i < o1.size(); i++) {
if (!o1.get(i).equals(o2.get(i))) return o1.get(i) - o2.get(i);
}
return 0;
}
});
void dfs(int[] nums,List<Integer>list,int k,int start,int target){
if(list.size()==k&&list.get(0)+list.get(1)+list.get(2)+list.get(3)==target) {result_set.add(new ArrayList<>(list));return;}
for (int i =start ; i <nums.length ; i++) {
list.add(nums[i]);
dfs(nums,list,k,i+1,target);
list.remove(list.size()-1);
}
}
總結:
回溯法:【多叉樹+棧/隊列】來分析
dp:【二維表/一維表】
遞歸:
二分:
多指針: