持续更新
2.Add Two Numbers
循环的时候要按照while(l1!=null || l2!=null)这样,判断条件应该为或。因为比如99+9999,这种情况,或就可以全部包含
3. Longest Substring Without Repeating Characters
其中一个解法 滑动窗口,就是在一个字符串中,从头到尾,一个i-j范围区间内,从前到后搜,s.chartAt(j)如果在set中没有,则j++,如果有,则把s.chartAt(i)从set中踢出,i++,j++,吧s.chartAt(j)添加到集合中去。
45.Jump Game II
http://www.cnblogs.com/grandyang/p/4373533.html
看第一个链接的解释
https://blog.csdn.net/linhuanmars/article/details/21356187
看第二个链接的做法
53.Maximum Subarray
从第一个开始加,大于零了就留着,小于了就放,看下一个
https://blog.csdn.net/linhuanmars/article/details/21314059
使用局部最优和全局最优解法,基本思路就是维护两个变量,一个是全局最优,就是到当前元素为止最优的解是,一个是局部最优,就是必须包含当前元素的最优的解。
这个局部变量local仅仅是累加所有的元素,global才是最终的值,global由之前的global和local的最大值得到。
55.Jump Game
动态规划的方法见此链接:http://www.cnblogs.com/grandyang/p/4371526.html
这里的剩余步数的意思是到达此还需要多少步
贪心算法也可以看这个
70. Climbing Stairs
动态规划,三个重要概念:最优子结构、边界、状态转移公式
https://www.sohu.com/a/153858619_466939,这个链接里面有详细的讲解和两个经典的问题。
对于本题:
分析出f(10)=f(9)+f(8),其中f(9)和f(8)就是f(10)的最优子结构
当只有1级或2级台阶的时候,可以直接得到结果,所以f(1)和f(2)是问题的边界
f(n)=f(n-1)+f(n-2)是阶段与阶段之间的状态转移方程,决定每一个阶段和下一个阶段的关系
以上三个概念是问题的建模
而以上并不是真正的动态规划,以上为从后向前看。下面的方法是从前向后看,也是自底向上看。
真正应该从前向后看,f(1)=1,f(2)=2,f(3)=f(1)+f(2)。即f(3)只依赖于f(1)和f(2)。同理向后。i.e. 每一次迭代只要保留前两个状态,就可以推出新的状态。
台阶的问题是最简单的,因为只有一个变化维度。可以看链接里的黄金矿工问题,有两个变化维度。
94.Binary Tree Inorder Traversal 树中序遍历
递归和非递归
class TreeNode{
int val;
TreeNode left;
TreeNode rigth;
TreeNode(int val){
this.val = val;
}
}
这个链接三种遍历都有:https://blog.csdn.net/benweizhu/article/details/7930697
https://blog.csdn.net/kerryfish/article/details/24309617
123.Best Time to Buy and Sell Stock III
链接:https://blog.csdn.net/linhuanmars/article/details/23236995
没看懂
169. Majority Element
solution 6:就是假设第一个数字是,然后有个临时变量存着它,遍历,第二个数如果是,count+1,不是则count-1。如果count==0,则转向下一个数字,就是说这下一个数字用临时变量存着,再下一个数字如果和它相等则加一,不等则减一,最后返回临时变量的数字。
198.House Robber
解法动态规划,简写dp。相当于在一列数组中取出一个或多个不相邻数,使其和最大。对于这类求极值的问题首先考虑动态规划Dynamic Programming来解,我们维护一个一位数组dp,其中dp[i]表示到i位置时不相邻数能形成的最大和,那么递推公式怎么写呢,我们先拿一个简单的例子来分析一下,比如说nums为{3, 2, 1, 5},那么我们来看我们的dp数组应该是什么样的,首先dp[0]=3没啥疑问,再看dp[1]是多少呢,由于3比2大,所以我们抢第一个房子的3,当前房子的2不抢,所以dp[1]=3,那么再来看dp[2],由于不能抢相邻的,所以我们可以用再前面的一个的dp值加上当前的房间值,和当前房间的前面一个dp值比较,取较大值当做当前dp值,所以我们可以得到递推公式dp[i] = max(num[i] + dp[i - 2], dp[i - 1]), 由此看出我们需要初始化dp[0]和dp[1],其中dp[0]即为num[0],dp[1]此时应该为max(num[0], num[1])。
链接里有其他方法:https://www.programcreek.com/2014/03/leetcode-house-robber-java/
一个方法是开辟一个数组,另外一个方法是用两个变量。
自己的想法:就可以弄一个比如说7个元素的数组,然后一个个加看。因为每个元素的值只和前两个元素油管,所以就可以照着那7个元素的数组柳一遍看。注意dp[1]也要比较数组第一个元素和第二个元素的大小来做决定。以此,就可以只用三个变量来完成上面的开辟新数组的方法。
303.Range Sum Query - Immutable
可能出题的重点是Note:You may assume that array does not change
所以可以将nums数组进行改变,即,把每个元算改为前面所有元素相加的和
345.Reverse Vowels of a String
可以按照这个方法,用一个栈,遍历两次
public String reverseVowels(String s)
{
StringBuilder sb = new StringBuilder();
Stack vowelStack = new Stack();
for(char c: s.toCharArray())
{
if(isVowel(c))
{
vowelStack.push(c);
}
}
for(char c: s.toCharArray())
{
if(isVowel(c))
{
sb.append(vowelStack.pop());
}
else
{
sb.append(Character.toString(c));
}
}
return sb.toString();
}
public Boolean isVowel(Character value)
{
char val = Character.toLowerCase(value);
if(val == 'a' || val == 'e' || val == 'i' || val == 'o' || val == 'u')
{
return true;
}
return false;
}
或者双指针,从后向前遍历,和从前向后遍历,然后两个互换。
private final static HashSet<Character> vowels = new HashSet<>(Arrays.asList('a', 'e', 'i', 'o', 'u', 'A', 'E', 'I', 'O', 'U'));
public String reverseVowels(String s) {
int i = 0, j = s.length() - 1;
char[] result = new char[s.length()];
while (i <= j) {
char ci = s.charAt(i);
char cj = s.charAt(j);
if (!vowels.contains(ci)) {
result[i++] = ci;
} else if (!vowels.contains(cj)) {
result[j--] = cj;
} else {
result[i++] = cj;
result[j--] = ci;
}
}
return new String(result);
}
347.Top K Frequent Elements
使用桶排序,这个的思路就是首先把所有数字遍历一遍,然后用hashmap存一下。
hashmap<数字,出现的频率>,然后构造一个数组,为List<integer>类型的数组,
使用List<Integer>作为数组元素的原因是防止有出现频率相同的元素。
将hashmap中的元素出现的频率作为桶排序的数组的下标那个,然后将出现的元素add到数组中的list元素。
最后从后向前遍历取出。
public List<Integer> topKFrequent(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<>();
for(int key:nums) {
map.put(key,map.getOrDefault(key,0)+1);
}
List<Integer>[] list = new ArrayList[nums.length+1];//这只是一个List类型的数组
for(int key:map.keySet()){
int frequency = map.get(key);
if(list[frequency] == null ){
list[frequency] = new ArrayList();
}
list[frequency].add(key);
}
List<Integer> result = new ArrayList(k);
for(int i=list.length-1;i>=0 && result.size()<k; i--) {
if(list[i]!=null) {
for(int j = 0;j<list[i].size() && j<k;j++) {
result.add(list[i].get(j));
}
}
}
return result;
}
387. First Unique Character in a String
依旧类似347,451的桶排序思想
public int firstUniqChar(String s) {
int[] fre = new int[26];
for(int i=0;i<s.length();i++){
fre[s.charAt(i)-'a']++;
}
for(int i=0;i<s.length();i++){
if(fre[s.charAt(i)-'a']==1)
return i;
}
return -1;
}
401.Binary Watch
backtracking回溯法
要解决的问题大致具有这样的特征,为了得到问题的解,需要进行若干步骤,每一步的抉择都是相同的,每一步都是在上一步的基础上完成的,需要记录之前的轨迹,直到终点情况,不过有可能是正确也有可能是错误。
https://blog.csdn.net/u010900754/article/details/55094478
回溯的另一个讲解
https://segmentfault.com/a/1190000006121957
435.Non-overlapping Intervals
用贪心,把intervals给排序,按照end的大小,然后选end最小的,这样后面的空间才会大一些。
public int eraseOverlapIntervals(Interval[] intervals) {
if(intervals.length==0){
return 0;
}
Arrays.sort(intervals,new Comparator<Interval>(){
@Override
public int compare(Interval o1,Interval o2){
return o1.end-o2.end;
}
});
int cnt = 1;
int end = intervals[0].end;
for(int i=1;i<intervals.length;i++){
if(intervals[i].start<end){
continue;
}
end = intervals[i].end;
cnt ++;
}
return intervals.length - cnt;
}
451. Sort Characters By Frequency
同347原理
public String frequencySort(String s) {
Map<Character,Integer> map = new HashMap<>();
for(char c :s.toCharArray()) {
map.put(c,map.getOrDefault(c,0)+1);
}
List<Character>[] list = new ArrayList[s.length()+1];
for(char c:map.keySet()){
int f = map.get(c) ;
if(list[f] == null) {
list[f] = new ArrayList();
}
list[f].add(c);
}
StringBuilder sb = new StringBuilder();
for(int i=list.length-1;i>=0;i--){
if(list[i] == null) {
continue;
}
for(char c : list[i]){
//下面的for循环的意思是,字母可能会重复,所以要append上j次。
for(int j=0;j<i;j++){
sb.append(c);
}
}
}
return sb.toString();
}
452. Minimum Number of Arrows to Burst Balloons
这个题目的意思是,给的区间范围是气球的直径,然后飞镖从x轴垂直的方向扎,看最少扎几次。
下面的代码中,points是个数组类型的数组,即此数组中的元素是小数组,有两个元素。所以array.sort()中的Comparator的泛型需要写的就是int[]。
public int findMinArrowShots(int[][] points) {
if(points.length<=0){
return 0;
}
Arrays.sort(points, new Comparator<int[]>() {
@Override
public int compare(int[] o1, int[] o2) {
return o1[1] - o2[1];
}
});
int cnt = 1;
int end = points[0][1];
for(int i=1;i<points.length;i++){
//这个if是,首先points是个数组类型的数组,即此数组中的元素是小数组,有两个元素
//points[i][0]是直径的开头
if(points[i][0]<=end){
continue;
}
cnt++;
end = points[i][1];
}
return cnt;
}
633.Sum of Square Numbers
sloution里面的方法4,就是数字a从零开始遍历到根号c,然后在每一次循环中,二分查找b的值,因为数字a确定了,所以就看a方加b方是否等于c,每次用mid=(s+e)/2,看mid*mid是否等于b。这样。
然后还可以用这种方法
public boolean judgeSquareSum(int c) {
int i = 0, j = (int) Math.sqrt(c);
while (i <= j) {
int powSum = i * i + j * j;
if (powSum == c) {
return true;
} else if (powSum > c) {
j--;
} else {
i++;
}
}
return false;
}
680. Valid Palindrome II
1.solution里面的brute force的思路是从头到尾删除每一个字母,然后判断是不是回文,然后再添回去这个字母,然后删除下一个字母,再判断是不是回文。
2.Greedy的翻译是:如果string的开头和结尾字符是相同的,那么里面部分的字母是不是回文决定了整个string是不是回文。
其中isPalindrome()函数里面,s.charAt(j-k+i),可以理解为j-(k-i),可以设i=2,j=8,k=4,这样就可以看出来了。还可以用while循环,即:
private boolean isPalindrome(String s, int i, int j) {
while (i < j) {
if (s.charAt(i++) != s.charAt(j--)) {
return false;
}
}
return true;
}
746. Min Cost Climbing Stairs类似198题。可以用一个数组来存储之前的数值,也可以用两个变量来存。
用一个数组存的话,则dp[i]表示爬到第i层的最小cost。
https://www.cnblogs.com/grandyang/p/8343874.html
dp[i]=min ( dp[i-2] + cost[i-2] , dp[i-1] + cost[i-1] ) , 返回最后一个数字dp[n]
如果用一个变量存,递推公式为f_current=cost[i]+f1+f2
其中f_current代表走到了当前cost[i]数组i的位置的时候的消费
然后f1代表距离f_current两步的cost[i]的消费
f2代表距离f_current一步的所有消费
f1代表距离f_current两步的所有消费
当到了cost[i]最后一个元素的时候,前面有两个计算得到的结果,一个f1,一个f2
只要计算这两个的元素的大小就可以得到最终结果