Leetcode各题 个人理解(持续更新)LeetCode java

持续更新

 

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

只要计算这两个的元素的大小就可以得到最终结果

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值