Title: leetcode算法精简总结第一遍:
Tags: java 算法
Slug: java-jichu
Category: java语言
Summary:算法
# 第一部分:String #
1、 Reverse String
> Example:
> Given s = "hello", return "olleh".
tip:
Array---->String(数组转字符串):
* return new String(array);
* return String.valueOf(array);
二分查找交换:循环长度的一半,最后一个和第一个交换
public class Solution {
public String reverseString(String s) {
if (s == null || s.length() < 2){
return s;
}
char[] array = s.toCharArray();
int j = array.length;
for (int i = 0; i < j / 2; i++){
char temp = array[i];
array[i] = array[j - i - 1];
array[j - i - 1] = temp;
}
return new String(array);
//way2 return String.valueOf(array);
}
}
复杂度分析:
O(N),except Binary recursion(O(N)=logn),other O(N)=n
70、Climbing Stairs:
> You are climbing a stair case. It takes n steps to reach to the top.
> Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
注意:0个台阶对应1种方法。
思路:[http://blog.crayygy.com/14599905787744.html](http://blog.crayygy.com/14599905787744.html)
> 取决于上一个和上上一个台阶:这个人爬n层楼梯,那么它也不是一下子就可以爬这么高的,他只有两个选择,要么从n-2层爬过来,要么从n-1层爬过来。除此之外,他没有别的选择。
>
1、递归法(leetcode 超时)空间O(1.618N)时间复杂度O(N)
public class Solution {
public int climbStairs(int n) {
/***
递归
**/
if (n <= 2){
return n;
}
return climbStairs(n - 1) + climbStairs(n - 2);
}
}
2、动态规划 空间O(N)时间复杂度O(N)记得对2求雨
public class Solution {
public int climbStairs(int n) {
/***
动态
**/
if (n < 2){
return 1;
}
int[] dp = new int[2];
dp[0] = 1;
dp[1] = 1;
for (int i = 2; i <= n; i++){
dp[i % 2] = dp[(i - 1) % 2] + dp[(i - 2) % 2];
}
return dp[n%2];
}
}
public class Solution {
public int climbStairs(int n) {
/***
动态,best
**/
int[] dp = new int[]{1, 1, 2};
if (n < 3){
return dp[n];
}
for (int i = 3; i <= n; i++){
dp[0] = dp[1];
dp[1] = dp[2];
dp[2] = dp[1] + dp[0];
}
return dp[2];
}
}
3、波菲利纳数列:O(logn)o(1)
public class Solution {
public int climbStairs(int n) {
/***
fibonacci
**/
double sqrt5 = Math.sqrt(5.0);
double pfi = (1.0 + sqrt5) / 2;
return (int) ((Math.pow(pfi, n + 1) - Math.pow(-pfi, -(n + 1))) / sqrt5 + 0.5);
}
}
387、First Unique Character in a String(第一个不重复的字符)
>Given a string, find the first non-repeating character in it and return it's index. If it doesn't exist, return -1.
> s = "leetcode"
> return 0.
>
> s = "loveleetcode",
> return 2.
**tips:注意把字符串转换成char[]数组的效率更高。**
1、15ms,O(N),O(1).思路:alp统计26个字母出现次数;先遍历字符串数组,然后查找alp表第一个次数为1的位置。
Public class Solution{
public int firstUniqChar(String s) {
int[] alp =new int[26];
char[] arr =s.toCharArray();
for(char c : arr ){
alp[c-'a']++;
}
for(int i=0;i
}
return -1;
}
public int firstUniqChar(String s) {
if(s.length() == 0 || s == null) return -1;
char[] chars = s.toCharArray();
int[] count = new int[26];
for(int i=0; i
}
int index = s.length();
for(int i=0; i<26; i++){
if(count[i] == 1){
int idx = s.indexOf('a' + i);
index = Math.min(idx, index);
}
}
return index == s.length() ? -1 : index; //all the chars are not unique
}
2、16ms,O(N),O(1).思路:先给26个字母频率统一赋初值-1;遍历字符串数组,pos记录26个字符的位置,重复的赋值-2;循环pos,找出最小的正数(包括0),该数就是第一个不重复的字符的位置。
public class Solution {
public int firstUniqChar(String s) {
int[] pos = new int[26];
for(int i=0; i<26; i++){
pos[i]=-1;
}
char[] arr = s.toCharArray();
for (int i = 0; i
if (pos[idx]==-1){
pos[idx]=i;
}else {
pos[idx]=-2;
}
}
int ret = arr.length;
for(int i = 0; i < 26; i++){
if(pos[i]>=0){
ret = Math.min(ret,pos[i]);
}
}
return ret == arr.length ? -1 : ret; //all the chars are not unique
}
}
3、与第一种类似,区别是:count统计26个字母出现次数;先遍历次数表找到次数为1的字符,然后比较字符在字符串中位置谁靠前。
public class Solution {
public int firstUniqChar(String s) {
int l=s.length();
if(l==0) return -1;
if(l==1) return 0;
for(int i=0;i
if(i
if(s.indexOf(c,i+1)==-1 && s.indexOf(c)==i) return i;
}
else{
if( s.indexOf(c)==i) return i;
}
}
return -1;
}
}
415、 Add Strings
> Given two non-negative numbers num1 and num2 represented as string, return the sum of num1 and num2.
>
> Note:
>
> The length of both num1 and num2 is < 5100.
> Both num1 and num2 contains only digits 0-9.
> Both num1 and num2 does not contain any leading zero.
> You must not use any built-in BigInteger library or convert the inputs to integer directly.
tip:StringBuilder存储结果;设置标志位;最大串的长度当循环截至;变量val=标志位,**从后往前**,val依次加第一个串的字符,第二个串的字符。个位数加入到结果,最后判断有无标志位,加入结果,结果反转并转为字符串。
public class Solution {
public String addStrings(String num1, String num2) {
StringBuilder sb = new StringBuilder();
int l1 = num1.length();
int l2 = num2.length();
int max = Math.max(l1, l2);
int carry = 0;
for (int i = 0; i < max; i++) {
int val = carry;
if (i < l1) {
val += num1.charAt(l1-i-1) - '0';
}
if (i < l2) {
val += num2.charAt(l2-i-1) - '0';
}
sb.append(val % 10);
carry = val / 10;
}
if (carry > 0) {
sb.append(carry);
}
return sb.reverse().toString();
}
}
not AC原因:
1、0+0,无结果--->i起始为0
2、2位数加错--->l1-i-1,不是i
459. Repeated Substring Pattern(是否由重复子串组成)
> Given a non-empty string check if it can be constructed by taking a substring of it and appending multiple copies of the substring together. You may assume the given string consists of lowercase English letters only and its length will not exceed 10000.
>
> Example 1:
> Input: "abab"
>
> Output: True
>
> Explanation: It's the substring "ab" twice.
> Example 2:
> Input: "aba"
>
> Output: False
解法:[kmp原理:](http://blog.csdn.net/v_july_v/article/details/7041827)res[]记录每个字符的部分匹配表,最长公共前后缀个数的值。算法复杂度O(n)。
kmp方法:next存储前后缀最大相同子串长度。cur当前字符与下一个字符相同,存在一个相同前后缀,不相同就继续往后比,如果cur 是第一个后进,如果cur不是cur回退。
public class Solution {
public boolean repeatedSubstringPattern(String str) {
int len = str.length();
int[] next = new int[len];
next[0] = 0;
int cur = 0;
int j = 1;
while (j < len) {
char c = str.charAt(j);
if (c == str.charAt(cur)) {
next[j++] = ++cur;
} else {
if (cur == 0) {
next[j++] = 0;
} else {
cur = next[cur - 1];
}
}
}
return next[len - 1] > 0 && len % (len - next[len - 1]) == 0;
}
}
345. Reverse Vowels of a String:反转元音字符串
> Write a function that takes a string as input and reverse only the vowels of a string.
>
> Example 1:
> Given s = "hello", return "holle".
>
> Example 2:
> Given s = "leetcode", return "leotcede".
public class Solution {
public String reverseVowels(String s) {
int[] pos = new int[s.length()];
int cnt = 0;
HashSet
vowel.add('a');
vowel.add('e');
vowel.add('i');
vowel.add('o');
vowel.add('u');
vowel.add('A');
vowel.add('E');
vowel.add('I');
vowel.add('O');
vowel.add('U');
for (int i = 0; i < s.length(); i++) {
if (vowel.contains(s.charAt(i))) {
pos[cnt] = i;
cnt++;
}
}
char[] ans = new char[s.length()];
ans = s.toCharArray();
for (int i = 0; i < cnt; i++) {
ans[pos[i]] = s.charAt(pos[cnt - i - 1]);
}
return String.valueOf(ans);
}
}
优化:
public class Solution {
public String reverseVowels(String s) {
int[] pos = new int[s.length()];
int cnt = 0;
HashSet
vowel.add('a');
vowel.add('e');
vowel.add('i');
vowel.add('o');
vowel.add('u');
vowel.add('A');
vowel.add('E');
vowel.add('I');
vowel.add('O');
vowel.add('U');
for (int i = 0; i < s.length(); i++) {
if (vowel.contains(s.charAt(i))) {
pos[cnt] = i;
cnt++;
}
}
char[] ans = new char[s.length()];
ans = s.toCharArray();
for (int i = 0; i < cnt/2; i++) {
char temp = ans[pos[i]];
ans[pos[i]] = ans[pos[cnt - i - 1]];
ans[pos[cnt - i - 1]] = temp;
}
return String.valueOf(ans);
}
}
434. Number of Segments in a String(字符串由多少分段组成)
> Count the number of segments in a string, where a segment is defined to be a contiguous sequence of non-space characters.
>
> Please note that the string does not contain any non-printable characters.
>
> Example:
>
> Input: "Hello, my name is John"
> Output: 5
1、O(n)o(1)当前不为空,前一个为空。
public int countSegments(String s) {
int res=0;
for(int i=0; i
res++;
return res;
}
2、O(n)O(n)split():时间复杂度高O(m*n)用StringTokenizer()方法会高效
public class Solution {
public int countSegments(String s) {
String ss = s.trim();
if (ss.length() == 0) {
return 0;
} else {
return ss.split("\\s+").length;
}
}
}
**438. Find All Anagrams in a String (返回变位词出现的位置) 不太懂,待求教**O(n)
Given a string s and a non-empty string p, find all the start indices of p's anagrams in s.
Strings consists of lowercase English letters only and the length of both strings s and p will not be larger than 20,100.
The order of output does not matter.
Example 1:
Input:
s: "cbaebabacd" p: "abc"
Output:
[0, 6]
Explanation:
The substring with start index = 0 is "cba", which is an anagram of "abc".
The substring with start index = 6 is "bac", which is an anagram of "abc".
public class Solution {
public List
List
if (s == null || s.length() == 0 || p == null || p.length() == 0) {
return list;
}
int [] hash = new int[256];
for (char c : p.toCharArray()) {
hash[c]++;
}
int left = 0;
int right = 0;
int count = p.length();
while (right < s.length()) {
if (hash[s.charAt(right++)]-- >= 1) {
count--;
}
if (count == 0) {
list.add(left);
}
if (right - left == p.length() && hash[s.charAt(left++)]++ >= 0){
count++;
}
}
return list;
}
}
205. Isomorphic Strings(同构字符串):判断是否同构字符串
> Given two strings s and t, determine if they are isomorphic.
>
> Two strings are isomorphic if the characters in s can be replaced to get t.
>
> All occurrences of a character must be replaced with another character while preserving the order of characters. No two characters may map to the same character but a character may map to itself.
>
> For example,
> Given "egg", "add", return true.
>
> Given "foo", "bar", return false.
>
> Given "paper", "title", return true.
public class Solution {
public boolean isIsomorphic(String s, String t) {
int [] m = new int[512];
for (int i = 0; i < s.length(); i++) {
char a = s.charAt(i);
char b = t.charAt(i);
if (m[(int) a] != m[(int) b + 256]) {
return false;
}
m[(int) b + 256] = i + 1;
m[(int) a] = i + 1;
}
return true;
}
}
339.Nested List Weight Sum 嵌套链表权重和
注意:变量命名必须以小写开头驼峰法。
Given a nested list of integers, return the sum of all integers in the list weighted by their depth.
Each element is either an integer, or a list -- whose elements may also be integers or other lists.
Example 1:
Given the list [[1,1],2,[1,1]], return 10. (four 1's at depth 2, one 2 at depth 1)
Example 2:
Given the list [1,[4,[6]]], return 27. (one 1 at depth 1, one 4 at depth 2, and one 6 at depth 3; 1 + 4*2 + 6*3 = 27)
/**NestedInteger接口有以下三个方法。
* // This is the interface that allows for creating nested lists.
* // You should not implement it, or speculate about its implementation
* public interface NestedInteger {
*
* // @return true if this NestedInteger holds a single integer,
* // rather than a nested list.
* public boolean isInteger();
*
* // @return the single integer that this NestedInteger holds,
* // if it holds a single integer
* // Return null if this NestedInteger holds a nested list
* public Integer getInteger();
*
* // @return the nested list that this NestedInteger holds,
* // if it holds a nested list
* // Return null if this NestedInteger holds a single integer
* public List
* }
*/
public class Solution {
public int depthSum(List
// Write your code here
if (nestedList == null || nestedList.size() == 0) {
return 0;
}
int sum = 0;
Queue
for (NestedInteger nestedInt : nestedList) {
queue.offer(nestedInt);//入栈,对于有限长度,效果比add好
}
int depth = 0;
while (!queue.isEmpty()) {
int size = queue.size();
depth++;
for (int i = 0; i < size; i++) {
NestedInteger nestedInt = queue.poll();//poll取出队首元素,并删除
if (nestedInt.isInteger()) {
sum += nestedInt.getInteger() * depth;
} else {
for (NestedInteger innerInt : nestedInt.getList()) {
queue.offer(innerInt);
}
}
}
}
return sum;
}
}
412. Fizz Buzz :3的倍数输出Fizz,5的倍数输出Buzz,同时是3和5的倍数,就输出FizzBuzz.O(N)O(N)
NotAC:elseif后才可加条件,else后不可加条件。结果为字符串型:String.ValueOf(i)
public class Solution {
public List
List
for (int i = 1; i <= n; i++) {
if (i % 15 == 0) {
results.add("FizzBuzz");
} else if (i % 5 == 0) {
results.add("Buzz");
} else if (i % 3 == 0) {
results.add("Fizz");
} else {
results.add(String.valueOf(i));
}
}
return results;
}
}
359.Logger Rate Limiter 记录速率限制器:这道题让我们设计一个记录系统每次接受信息并保存时间戳,然后让我们打印出该消息,前提是最近10秒内没有打印出这个消息。
思路:这不是一道难题,我们可以用哈希表来做,建立消息和时间戳之间的映射,如果某个消息不再哈希表表,我们建立其和时间戳的映射,并返回true。如果应经在哈希表里了,我们看当前时间戳是否比哈希表中保存的时间戳大10,如果是,更新哈希表,并返回true,反之返回false,
public class Logger {
private HashMap
/** Initialize your data structure here. */
public Logger() {
map = new HashMap
}
/** Returns true if the message should be printed in the given timestamp, otherwise returns false.
If this method returns false, the message will not be printed.
The timestamp is in seconds granularity. */
public boolean shouldPrintMessage(int timestamp, String message) {
if(map.containsKey(message)&&(timestamp-map.get(message))<10)
{
return false;
}
map.put(message,timestamp);
return true;
}
}
/**
* Your Logger object will be instantiated and called as such:
* Logger obj = new Logger();
* boolean param_1 = obj.shouldPrintMessage(timestamp,message);
*/
463. [Island Perimeter: 计算小岛周长](https://leetcode.com/problems/island-perimeter/)
思路:数组元素为1,增加4条边,有一个相邻的,周长减少2。
notac: 数组越界,一定先判定i
public class Solution {
public int islandPerimeter(int[][] grid) {
int result = 0;
int height = grid.length;
int width = grid[0].length;
for (int i = 0; i < height; i++) {
for (int j = 0; j < width; j++) {
if (grid[i][j] == 1) {
result += 4;
if (i < height - 1 && grid[i + 1][j] == 1) {
result -= 2;
}
if (j < width - 1 && grid[i][j + 1] == 1) {
result -= 2;
}
}
}
}
return result;
}
}
346.Moving Average from Data Stream 从数据流中移动平均值
Given a stream of integers and a window size, calculate the moving average of all integers in the sliding window.
For example,
MovingAverage m = new MovingAverage(3);
m.next(1) = 1
m.next(10) = (1 + 10) / 2
m.next(3) = (1 + 10 + 3) / 3
m.next(5) = (10 + 3 + 5) / 3
> 思路:这道题定义了一个MovingAverage类,里面可以存固定个数字,然后我们每次读入一个数字,如果加上这个数字后总个数大于限制的个数,那么我们移除最早进入的数字,然后返回更新后的平均数,这种先进先出的特性最适合使用队列queue来做,而且我们还需要一个double型的变量sum来记录当前所有数字之和,这样有新数字进入后,如果没有超出限制个数,则sum加上这个数字,如果超出了,那么sum先减去最早的数字,再加上这个数字,然后返回sum除以queue的个数即可
>
该方法用双端队列实现,也可用队列实现,注意变量名要不同。
public class MovingAverage {
private Deque
private int size;
private double sum;
public MovingAverage(int num) {
this.num = size;//这个两个变量名要不同
}
public double next(int val) {
if (deque.size() == size) {
sum -= deque.pollFirst();
}
deque.offerLast(val);
sum += val;
return sum / deque.size();
}
}
266.Palindrome Permutation 回文全排列
Given a string, determine if a permutation of the string could form a palindrome.
For example,
"code" -False, "aab" -True, "carerac" -True.
hint:hashset的add、remove 及contains 方法的时间复杂度是一个常量 O(1)。
> 回文特性:那么根据题目中的提示,我们分字符串的个数是奇偶的情况来讨论,如果是偶数的话,由于回文字符串的特性,每个字母出现的次数一定是偶数次,当字符串是奇数长度时,只有一个字母出现的次数是奇数,其余均为偶数,
该算法O(n):set中插入字符,set中存在就删除该字符,最后统计set.size,如果多余1就说明不是回文。**空间复杂度不知道**,设置容量后O(1)
[set的容量问题](http://www.cnblogs.com/xiezie/p/5511840.html):默认初始容量是16,加载因子是0.75.即当 元素个数 超过 容量长度的0.75倍 时,进行扩容
每次自动扩容的效果不好,可以提前给他添加size.
注意:++i比i++少循环一次,但达到同样效果,在做迭代的时候,++i比i++好,省去了一个无名对象的构建跟析构成本
public class Solution {
public boolean canPermutePalindrome(String s) {
Set
for(int i=0; i
set.add(s.charAt(i));
else
set.remove(s.charAt(i));
}
return set.size()==0 || set.size()==1;
}
}
O(N),O(1)
public boolean canPermutePalindrome(String s) {
if (s == null || s.length() == 0) {
return false;
}
int[] chars = new int[128];
for (char c : s.toCharArray()) {
chars[(int) c]++;
}
int count = 0;
for (int i : chars) {
if (i % 2 == 1) {
count++;
}
}
if (count > 1) {
return false;
}
return true;
}
292.Nim Game.轮流取石子,一次只能取1-3块,你是第一个拿的人,谁拿最后一块石子就赢,判断你能否赢?
hint:N只要是4的倍数个,我们一定会输,所以对4取余即可
public class Solution {
public boolean canWinNim(int n) {
return n % 4 != 0;
}
}
293.Flip Game : 第一次反转的可能性
>For example, given s = "++++", after one move, it may become one of the following states:
[
"--++",
"+--+",
"++--"
]
这道题让我们把相邻的两个++变成--,每次判断当前字母是否为+,和之前那个字母是否为+,如果都为加,则将翻转后的字符串存入结果。
public List
List list = new ArrayList();
for (int i=-1; (i = s.indexOf("++", i+1)) >= 0; )//s.indexOf("要找到字符串",int indexfrom:从第几个索引开始找)
list.add(s.substring(0, i) + "--" + s.substring(i+2));
return list;
}
136. Single Number
>Given an array of integers, every element appears twice except for one. Find that single one.
>要求:线性复杂度,空间O(1)
lint:异或可用来交换元素。两个相同的数异或为0,任何数与0异或为原数。
1=3^1^2^2^3
//方法1
public class Solution{
public int singleNumber(int[] nums){
int res = 0;
res = nums[0];
for(int i = 1; i < nums.length; i++){
res = res ^ nums[i];
}
return res;
}
}
//方法2
public class Solution {
public int singleNumber(int[] nums) {
int res = 0;
for (int num : nums) res ^= num;
return res;
}
}
137.Single Number II 单独的数字之二:每个字符出现3次,只有一个出现2次。
>Given an array of integers, every element appears three times except for one. Find that single one.
利用计算机按位储存数字的特性来做的,这道题就是除了一个单独的数字之外,数组中其他的数字都出现了三次,那么还是要利用位操作 Bit Operation 来解此题。
我们可以建立一个32位的数字,来统计每一位上1出现的个数,我们知道如果某一位上为1的话,那么如果该整数出现了三次,对3去余为0,我们把每个数的对应位都加起来对3取余,最终剩下来的那个数就是单独的数字。
hint:各个位数相加,然后对3求余,各个位就是该数的二进制。|=:相当于两数相加。
public class Solution {
public int singleNumber(int[] nums) {
int res = 0;
int[] bitInt = new int[32];
for (int i = 0; i < 32; i++) {
for (int j = 0; j < nums.length; j++) {
bitInt[i] += (nums[j] >> i) & 1;
}
res |= (bitInt[i] % 3) << i;
}
return res;
}
}
260. Single Number III
>Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.
For example:
Given nums = [1, 2, 1, 3, 2, 5], return [3, 5].要求o(n) o(1)
思路:
(位运算,第一次异或得到了两个只出一次的结果,C = A XOR B。那么结果出现1的位置,这两个值必然有一个为1,一个为0.由此划分为两组数字。在进行一次异或就可得到结果。回归到Single Number II)flag:是找出C中bit位为1的,k是索引。
1、异或求出C=C = A XOR B
2、找出任意为1的位k和flag
3、再次异或找出这两个数
public class Solution {
public int singleNumber(int[] nums) {
int [] res = new int [2];
int tmp = 0;
for (int c : nums) {
tmp ^= c;
}
int flag = 0;
int k = -1;
while (flag != 0) {
k++;
flag = (tmp >> k) & 1;
}
for (int c : nums) {
if (((c >> k) & 1) == 1) {
res[0] ^= c;
} else {
res[1] ^= c;
}
}
return res;
}
}
371. Sum of Two Integers
>Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -.
>Example:
Given a = 1 and b = 2, return 3.
a^b=无进位的加法, (a&b)<<1取进位。
public class Solution {
public int getSum(int a, int b) {
while (b != 0) {
int carry = (a & b) << 1;
a = a ^ b;
b = carry;
}
return a ;
}
}
404. Sum of Left Leaves(求左叶子节点的和)
Find the sum of all left leaves in a given binary tree.
> Example:[3,9,20,null,null,15,7]
>
> 3
> / \
> 9 20
> / \
> 15 7
>
> There are two left leaves in the binary tree, with values 9 and 15 respectively. Return 24.
两种方法:递归和迭代
迭代:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if (root == null ) {
return 0;
}
int res = 0;
Stack
stack.push(root);
while (!stack.empty()) {
TreeNode treenode = stack.pop();
if (treenode.left != null) {
if (treenode.left.left == null && treenode.left.right == null) {
res += treenode.left.val;
} else {
stack.push(treenode.left);
}
}
if (treenode.right != null){
if (treenode.right.left != null || treenode.right.right != null) {
stack.push(treenode.right);
}
}
}
return res;
}
}
递归:
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if (root == null) {
return 0;
}
int ans = 0;
if (root.left != null) {
if (root.left.left == null && root.left.right == null) {
ans += root.left.val;
} else {
ans += sumOfLeftLeaves(root.left);
}
}
ans += sumOfLeftLeaves(root.right);
return ans;
}
}
精简:
public class Solution {
public int sumOfLeftLeaves(TreeNode root) {
if (root == null) {
return 0;
}
int ans = 0;
if (root.left != null && root.left.left == null && root.left.right == null) {
ans += root.left.val;
} else {
ans += sumOfLeftLeaves(root.left);
}
ans += sumOfLeftLeaves(root.right);
return ans;
}
}
用stack:是先序遍历,用queue是层序遍历。
112. Path Sum :树的路径,到叶子节点的和是否等于给出的值.DFS:深度优先算法
>Given a binary tree and a sum, determine if the tree has a root-to-leaf path such that adding up all the values along the path equals the given sum.
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public boolean hasPathSum(TreeNode root, int sum) {
if (root == null) {
return false;
}
if (root.left == null && root.right == null) {
return sum == root.val;
}
return hasPathSum(root.left, sum - root.val) || hasPathSum(root.right, sum -root.val);
}
}
notac:
注意:类型不同的不能同名,如sum和sums,某个节点的值为tree.val
113. Path Sum II 二叉树路径之和之二 (依然用DFS,)
>Given a binary tree and a sum, find all root-to-leaf paths where each path's sum equals the given sum.
>For example:
Given the below binary tree and sum = 22,
5
/ \
4 8
/ / \
11 13 4
/ \ / \
7 2 5 1
>return
>[
[5,4,11,2],
[5,8,4,5]
]
ArrayList实现,访问每个节点为O(1),linkedList会为O(n),
notac:integer错写成interger;传参没写参数名,没有;
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public List> pathSum(TreeNode root, int sum) {
List
List> res = new ArrayList
>();
pathSum(cur, res, root, sum);
return res;
}
public void pathSum(List> res, TreeNode root, int sum){
if (root == null) {
return;
}
cur.add(root.val);
if (root.left == null && root.right == null && root.val == sum) {
res.add(new ArrayList(cur));//一定要new一个对象,不然一直是都指向同一个对象
} else {
pathSum(cur, res, root.left, sum - root.val);
pathSum(cur,res, root.right, sum - root.val);
}
cur.remove(cur.size() - 1);//一定要回溯
}
}
**437. Path Sum III ** (不用从root--leave,只要其中一段之和相等即可)不造
Add to List QuestionEditorial Solution My Submissions。
Total Accepted: 9434
Total Submissions: 24383
Difficulty: Easy
Contributors: Stomach_ache
You are given a binary tree in which each node contains an integer value.
Find the number of paths that sum to a given value.
The path does not need to start or end at the root or a leaf, but it must go downwards (traveling only from parent nodes to child nodes).
The tree has no more than 1,000 nodes and the values are in the range -1,000,000 to 1,000,000.
Example:
root = [10,5,-3,3,2,null,11,3,-2,null,1], sum = 8
10
/ \
5 -3
/ \ \
3 2 11
/ \ \
3 -2 1
Return 3. The paths that sum to 8 are:
1. 5 -> 3
2. 5 -> 2 -> 1
3. -3 -> 11
思路:
递归来做,相当于先序遍历二叉树,对于每一个节点都有记录了一条从根节点到当前节点到路径,同时用一个变量curSum记录路径节点总和,然后我们看curSum和sum是否相等,相等的话结果res加1,不等的话我们来继续查看子路径和有没有满足题意的,做法就是每次去掉一个节点,看路径和是否等于给定值,注意最后必须留一个节点,不能全去掉了,因为如果全去掉了,路径之和为0,而如果假如给定值刚好为0的话就会有问题,
174. Dungeon Game(地老游戏,求出王子就公主的最小初始血量,注意,到达任何地方血量都应该>=1,)
tip:从最后往最前出发。动态规划,省略空间。建立一个和迷宫大小相同的二维数组用来表示当前位置出发的起始血量,最先初始化的是公主所在的房间的起始生命值,然后慢慢向第一个房间扩散,不断的得到各个位置的最优的起始生命值。递归方程为: 递归方程是dp[i][j] = max(1, min(dp[i+1][j], dp[i][j+1]) - dungeon[i][j]).
notac: 新建health数组时,else if 里的是h[][]-d[][];
public class Solution {
public int calculateMinimumHP(int[][] dungeon) {
if (dungeon.length == 0) {
return 0;
}
int w = dungeon[0].length;
int h = dungeon.length;
int[][] health = new int[h][w];
health[h - 1][w - 1] = Math.max(1, 1 - dungeon[h - 1][w - 1]);
for (int i = h - 2; i >= 0; i--) {
health[i][w - 1] = Math.max(1, health[i + 1][w - 1] - dungeon[i][w - 1]);
}
for (int j = w - 2; j >= 0; j--) {
health[h - 1][j] = Math.max(1, health[h - 1][j + 1] - dungeon[h - 1][j]);
}
for (int i = h - 2; i >= 0; i--) {
for (int j = w - 2; j >= 0; j--){
health[i][j] = Math.max(1,Math.min(health[i + 1][j] - dungeon[i][j], health[i][j + 1] - dungeon[i][j]));
}
}
return health[0][0];
}
}
64. Minimum Path Sum
Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.每次只能向右或向下移动一次。
我们维护一个二维的dp数组,其中dp[i][j]表示当前位置的最小路径和,递推式也容易写出来 dp[i][j] = grid[i][j] + min(dp[i - 1][j],
**Path Sum III :求任何一段路径之和为sum**不是很懂:
思路:相当于先序遍历二叉树,对于每一个节点都有记录了一条从根节点到当前节点到路径,同时用一个变量curSum记录路径节点总和,然后我们看curSum和sum是否相等,相等的话结果res加1,不等的话我们来继续查看子路径和有没有满足题意的,做法就是每次去掉一个节点,看路径和是否等于给定值,注意最后必须留一个节点,不能全去掉了,因为如果全去掉了,路径之和为0,而如果假如给定值刚好为0的话就会有问题。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
public class Solution {
public int pathSum(TreeNode root, int sum) {
HashMap
presum.put(0,1);
return helper(root, 0, sum, presum);
}
public int helper(TreeNode root, int sum, int target, HashMap
if (root == null) {
return 0;
}
sum += root.val;
int res = presum.getOrDefault(sum - target, 0);
presum.put(sum, presum.getOrDefault(sum, 0) + 1);
res += helper(root.right, sum, target, presum) + helper(root.left, sum, target, presum);
presum.put(sum, presum.get(sum) - 1);//不懂为啥要-1 Remove the current node so it wont affect other path
return res;
}
}
# 第二部分:array #
453. Minimum Moves to Equal Array Elements(使得数组中的元素变为相同的,要做多少次改变)
> Example:
>
> Input:
> [1,2,3]
>
> Output:
> 3
>
> Explanation:
> Only three moves are needed (remember each move increments two elements):
>
> [1,2,3] = [2,3,3] = [3,4,3] = [4,4,4]
解法:建立一个2元方程求要动M次,最后每个元素都变为f,
sum(array)+m*(n-1)=n*f
f-min(array)=m
求得m=sum(array)-n*min(array)
tips1: 除了一个元素外其他元素递增,相当于让一个元素递减。sum - 个数*最小值。
public class Solution {
public int minMoves(int[] nums) {
if (nums.length == 0) {
return 0;
}
int res = 0;
int min = nums[0];
for (int i = 1; i < nums.length; i++) {
if (nums[i] >= min) {
res += nums[i] - min;
} else {
res += (min - nums[i]) * i;
min = nums[i];
}
}
return res;
}
}
349. Intersection of Two Arrays 不包括重复的值
> Given two arrays, write a function to compute their intersection.
>
> Example:
> Given nums1 = [1, 2, 2, 1], nums2 = [2, 2], return [2].
方法:3种
1、先对两个数组排序。然后相同的元素加入res
2、二分查找:一个数组排序,遍历另一个数组,把遍历到的每个数字在排序号的数组中用二分查找法搜索,如果能找到则放入结果set中,这里我们用到了set的去重复的特性,最后我们将set。
3、tip: 建立两个hashset,第一个存储nums1的值,第二个存储共有的值,最后转换为数组。
转换为数组的方法:
1、循环
2、sream:return list.stream().mapToInt(i->i).toArray();
public class Solution {
public int[] intersection(int[] nums1, int[] nums2) {
Set
Set
for (int i : nums1) {
set1.add(i);
}
for (int i : nums2) {
if (set1.contains(i)) {
set2.add(i);
}
}
int[] result = new int[set2.size()];
int j = 0;
for (Integer i : set2) {
result[j++] = i;
}
return result;
}
}
350. Intersection of Two Arrays II (重复值)注意说内存限制
用hashmap
1、如果数组排序了就用第一种
2、如果只有nums2内存限制,就先将nums1加入hashmap, 如果都限制内存,就都排序然后一个一个取出比较
3、如果nums1.的规模小,就hash
public class Solution {
public int[] intersect(int[] nums1, int[] nums2) {
Map
int[] result = new int[nums1.length];
int count = 0;
for (Integer i : nums1) {
map.put(i,map.getOrDefault(i, 0) + 1);
}
for (Integer i : nums2) {
Integer c = map.get(i);
if (c != null && c > 0) {
map.put(i, map.get(i) - 1);
result[count++] = i;
}
}
return Arrays.copyOf(result, count);
}
}
26. Remove Duplicates from Sorted Array (去重,求有序数组中不重复的元素个数,要求不许分配额外的数组。)
思路:有序数组,只需比较连个挨着的元素是否一样。当nums[k]!=nums[i],i所在的值就是当前值,否则i处的值就移到k处。k+1的值就是数组长度。
public class Solution {
public int removeDuplicates(int[] nums) {
int k = 0;
for (int i = 1; i < nums.length; i++) {
if (nums[k] != nums[i]) {
nums[++k] = nums[i];
}
}
return k + 1;
}
}
巧妙地方法:
public class Solution {
public int removeDuplicates(int[] nums) {
int i = 0;
for (int c : nums) {
if (i == 0 || c > nums[i-1]) {
nums[i++] = c;
}
}
return i;
}
}
80. Remove Duplicates from Sorted Array II(允许出现2次)
[方法:](http://www.sigmainfy.com/blog/leetcode-remove-duplicates-from-sorted-array-i-and-ii.html)
i表示新的索引。
O(N)O(1)
public class Solution {
public int removeDuplicates(int[] nums) {
if (nums == null) {
return 0;
}
int count = 1;
int i = 1;
int j = 1;
while (j < nums.length) {
if (nums[j] != nums[j - 1]) {
nums[i++] = nums[j];
count = 1;
} else {
if (count < 2) {
nums[i++] = nums[j];
count++;
}
}
++j;
}
return i;
}
}
83. Remove Duplicates from Sorted List
>For example,
>Given 1->1->2, return 1->2.
>Given 1->1->2->3->3, return 1->2->3.
tips:定义个指针指向该链表的第一个元素,然后第一个元素和第二个元素比较,如果重复了,则删掉第二个元素,如果不重复,指针指向第二个元素。
public class Solution {
public ListNode deleteDuplicates(ListNode head) {
if (head == null) {
return null;
}
ListNode node = head;
while (node.next != null) {
if (node.val == node.next.val) {
node.next = node.next.next;
} else {
node = node.next;
}
}
return head;
}
}
27. Remove Element
>Example:
Given input array nums = [3,2,2,3], val = 3
Your function should return length = 2, with the first two elements of nums being 2.
tip:两个指针。动尽量少的元素可以减少运行时间,将重复的元素被尾部的元素替换
public class Solution {
public int removeElement(int[] nums, int val) {
int end = nums.length - 1;
int i = 0;
while (i <= end) {
if (nums[i] == val) {
nums[i] = nums[end--];
} else {
i++;
}
}
return end + 1;
}
}
19. Remove Nth Node From End of List(删除倒数的第n个节点)
>For example,
> Given linked list: 1->2->3->4->5, and n = 2.
> After removing the second node from the end, the linked list becomes 1->2->3->5.
要求:一次遍历,就删除掉。
tip:preDelete,head两个指针,head先移动n个位置,如果此时fast为空,说明不溢出。然后两个指针一起移动,当head为空时,preDelete恰好到该移除的节点前一个节点。一定放一个前缀节点指向head,防止空指针异常和省略了判断fast移动了n+1的判断;
public class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
if (n <= 0) {
return null;
}
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode preDelete = dummy;
for (int i = 0; i < n; i++) {
if (head == null) {
return null;
}
head = head.next;
}
while (head != null) {
head = head.next;
preDelete = preDelete.next;
}
preDelete.next = preDelete.next.next;
return dummy.next;
}
}
203. Remove Linked List Elements
>Example
Given: 1 --> 2 --> 6 --> 3 --> 4 --> 5 --> 6, val = 6
Return: 1 --> 2 --> 3 --> 4 --> 5
tip:预先加一个空节点。留一个指针当head.
public class Solution {
public ListNode removeElements(ListNode head, int val) {
ListNode dumpty = new ListNode(0);
dumpty.next = head;
head = dumpty;
while(head.next != null) {
if (head.next.val == val) {
head.next = head.next.next;
} else {
head = head.next;
}
}
return dumpty.next;
}
}
82. Remove Duplicates from Sorted List II
> For example,
> Given 1->2->3->3->4->4->5, return 1->2->5.
> Given 1->1->1->2->3, return 2->3.
public class Solution {
public ListNode deleteDuplicates(ListNode head) {
if (head == null) {
return null;
}
ListNode dumpty = new ListNode(0 == head.val ? 1 : 0);//要让dumpt和head不同。
dumpty.next = head;
ListNode cur = head;
ListNode pre = dumpty;
head = dumpty;
// 只有前一个值不等与当前的,当前的 != 下一个。当前值才是唯一的
while (cur != null && cur.next != null) {
if (pre.val != cur.val && cur.val != cur.next.val) {
head.next = cur;
head = head.next;
}
pre = cur;
cur = cur.next;
}
//注意判断最后一个节点,最后一个cur节点
if (pre.val != cur.val) {
head.next = cur;
head = head.next;
}
//让最后一个的next为空。
head.next = null;
return dumpty.next;
}
}
注释的地方很重要
[LeetCode] Merge Sorted Array 混合插入有序数组
> Given two sorted integer arrays A and B, merge B into A as one sorted array.
>
> Note:
> You may assume that A has enough space (size that is greater or equal to m + n) to hold additional elements from B. The number of elements initialized in A and B are m andn respectively.
tip: A数组长度为n+m.从后往前插入比较,谁大放谁。最后谁剩下就全部填充到前面。if-else 比 3目比较( `nums1[index--] = nums1[m] > nums2[n] ? nums1[m--] : nums2[n--];`) 更快些
public class Solution {
public void merge(int[] nums1, int m, int[] nums2, int n) {
int index = m + n - 1;
--m;
--n;
while (m >= 0 && n >= 0) {
if (nums1[m] > nums2[n]) {
nums1[index--] = nums1[m--];
} else {
nums1[index--] = nums2[n--];
}
}
while (n >= 0) {
nums1[index--] = nums2[n--];
}
}
}
21. Merge Two Sorted Lists(合并两个有序链表)
>Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.
tip:依次比较两个链表的大小
1.o(n)空间
notac:最后判断谁不为空,head.next 错指向 l.next
public class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dumpty = new ListNode(0);
ListNode head = dumpty;
while (l1 != null && l2 != null) {
if (l1.val < l2.val) {
head.next = l1;
l1 = l1.next;
} else {
head.next = l2;
l2 = l2.next;
}
head = head.next;
}
if (l1 != null) {
head.next = l1;
} else {
head.next = l2;
}
return dumpty.next;
}
}
2.O(1)空间
if(l1 == null) return l2;
if(l2 == null) return l1;
if(l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l2.next, l1);
return l2;
}
这是queue的递归,始终重写同一块空间(BFS无论递归还是迭代,BFS都是属于队列结构的算法)
而stack 结构的递归,会占用很多额外的空间,规模庞大会堆栈溢出。(DFS)
57. Insert Interval(给一组有序的区间插入一个区间)
> Given a set of non-overlapping intervals, insert a new interval into the intervals (merge if necessary).
>
> You may assume that the intervals were initially sorted according to their start times.
>
> Example 1:
> Given intervals [1,3],[6,9], insert and merge [2,5] in as [1,5],[6,9].
>
> Example 2:
> Given [1,2],[3,5],[6,7],[8,10],[12,16], insert and merge [4,9] in as [1,2],[3,10],[12,16].
This is because the new interval [4,9] overlaps with [3,5],[6,7],[8,10].
tip: 遍历区间列表,分三种情况比较
注意:集合里foreach是有iterator实现的,用iterator更快
for循环适合访问顺序存储结构(arraylist)
Iterator适合访问链式存储结构(linkdelist)
数组插入的时间复杂度为O(N),查找O(1)
链表插入O(1),查找O(N)
1. o(1)空间,o(n)时间
public List
int i=0;
while(i
intervals.remove(i);
}
intervals.add(i,newInterval);
return intervals;
}
2. o(n),o(n)
if (newInterval == null || intervals == null) {
return intervals;
}
ArrayList
int insertPos = 0;
for (Interval interval : intervals) {
if (interval.end < newInterval.start) {
results.add(interval);
insertPos++;
} else if (interval.start > newInterval.end) {
results.add(interval);
} else {
newInterval.start = Math.min(interval.start, newInterval.start);
newInterval.end = Math.max(interval.end, newInterval.end);
}
}
results.add(insertPos, newInterval);
return results;
56. Merge Intervals
> Given a collection of intervals, merge all overlapping intervals.
>
> For example,
> Given [1,3],[2,6],[8,10],[15,18],
> return [1,6],[8,10],[15,18].
注意:一定要将i == n - 1 放到 start[i + 1] > end[i]前面,否则越界
public class Solution {
public List
int n = intervals.size();
int[] start = new int[n];
int[] end = new int[n];
for (int i = 0; i < n; i++) {
start[i] = intervals.get(i).start;
end[i] = intervals.get(i).end;
}
Arrays.sort(start);
Arrays.sort(end);
int j = 0;
List
for (int i = 0; i < n; i++){
if (i == n - 1 || start[i + 1] > end[i]) {
res.add(new Interval(start[j], end[i]));
j = i + 1;
}
}
return res;
}
}
not ac : collections 写错了;最后忘了添加最后的元素res.add();判断忘记判断相等的情况
public class Solution {
public List
if (intervals == null || intervals.size() < 2) {
return intervals;
}
Collections.sort(intervals, new IntervalComparator());
Interval last = intervals.get(0);
List
for (int i = 1; i < intervals.size(); i++) {
Interval cur = intervals.get(i);
if (cur.start < last.end) {
last.end = Math.max(cur.end, last.end);
} else {
res.add(last);
last = cur;
}
}
res.add(last);
return res;
}
private class IntervalComparator implements Comparator
public int compare(Interval a, Interval b) {
return a.start - b.start;
}
}
}
23. Merge k Sorted Lists(给定k个排序的list,合并成一个list)
> Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.
1. tip :priorityqueue是一个按大小顺序排列的队列。
> 这种解法利用了最小堆这种数据结构,我们首先把k个链表的首元素都加入最小堆中,它们会自动排好序。然后我们每次取出最小的那个元素加入我们最终结果的链表中,然后把取出元素的下一个元素再加入堆中,下次仍从堆中取出最小的元素做相同的操作,以此类推,直到堆中没有元素了,此时k个链表也合并为了一个链表,返回首节点即可
public class Solution {
private Comparator
public int compare(ListNode left, ListNode right) {
if (left == null) {
return 1;
} else if (right == null) {
return -1;
} else {
return left.val - right.val;
}
}
};
public ListNode mergeKLists(ListNode[] lists) {
if (lists == null || lists.length == 0) {
return null;
}
Queue
for (int i = 0; i < lists.length; i++) {
if (lists[i] != null) {
queue.add(lists[i]);
}
}
ListNode dumpty = new ListNode(0);
ListNode point = dumpty;
while(!queue.isEmpty()){
ListNode head = queue.poll();
point.next = head;
point = head;
if (head.next != null) {
queue.add(head.next);
}
}
return dumpty.next;
}
}
2.调用两个的排序,Divide & Conquer(ol较优)
> 分治法 Divide and Conquer Approach。简单来说就是不停的对半划分,比如k个链表先划分为合并两个k/2个链表的任务,再不停的往下划分,直到划分成只有一个或两个链表的任务,开始合并。
public class Solution {
public static ListNode mergeKLists(ListNode[] lists){
return partion(lists,0,lists.length-1);
}
public static ListNode partion(ListNode[] lists,int s,int e){
if(s==e) return lists[s];
if(s
ListNode l1=partion(lists,s,q);
ListNode l2=partion(lists,q+1,e);
return merge(l1,l2);
}else
return null;
}
//This function is from Merge Two Sorted Lists.
public static ListNode merge(ListNode l1,ListNode l2){
if(l1==null) return l2;
if(l2==null) return l1;
if(l1.val
return l1;
}else{
l2.next=merge(l1,l2.next);
return l2;
}
}
}
189. Rotate Array(至少3种方法)
>Rotate an array of n elements to the right by k steps.
>For example, with n = 7 and k = 3, the array [1,2,3,4,5,6,7] is rotated to [5,6,7,1,2,3,4].
1、3次反转,(0,n-k-1)(n-k,n-1)(0,n-1) O(1)空间
public class Solution {
public void rotate(int[] nums, int k) {
if (nums.length == 0) {
return;
}
k = k % nums.length;
reverse(nums, 0, nums.length - k -1);
reverse(nums, nums.length - k, nums.length - 1);
reverse(nums, 0, nums.length - 1);
}
public void reverse(int[] nums, int start, int end) {
while (start < end) {
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start++;
end--;
}
}
}
2、交换:不停的交换某两个数字的位置来实现旋转 O(1)空间
public class Solution {
public void rotate(int[] nums, int k) {
if (nums.length == 0) {
return;
}
int n = nums.length;
int start = 0;
while (n != 0 && (k %= n) != 0) {
for (int i =0; i < k; ++i) {
int temp = nums[i + start];
nums[i + start] = nums[i + start + n - k];
nums[i + start + n - k] = temp;
}
n -= k;
start += k;
}
}
}
3、O(n)
新建一个数组,对应传值
https://discuss.leetcode.com/topic/64936/java-several-solutions-which-do-you-think-the-best-it-s-appreciated-if-you-could-provided-its-pros-and-cons/3