LeetCode分类刷题

双指针

(1)167. 两数之和 II - 输入有序数组

(2)633. 平方数之和 

双指针去寻找两数平方和未target

注意r起点为Math.sqrt(target),因为target可为int中最大值2^31-1故,l^2+r^2可出现大于int。

注意用long存储减少溢出

 public boolean judgeSquareSum(int c) {
        long l=0,r=(long)Math.sqrt(c);
        //l,r也需要用long存储,不然会计算结果为int,再存给long那就已经被劫
        while(l<=r){
            long num = l*l+r*r;
            if(num<c){
                l++;
            }
            else if(num>c){
                r--;
            }
            else{
                return true;
            }
        }
        return false;
    }

(3)345. 反转字符串中的元音字母

/*
几点:String 可利用indexOf确定是否包含该字符。不包含返回-1
      String 可toCharArray()转化成char[]
       String(char[])可传入字符数组进行构造
*/
import java.util.*;
class Solution {
    public String reverseVowels(String s) {
        String re ="aAeEiIoOuU";
        char[] str = s.toCharArray();
        int i = 0,j=str.length-1;
        while(i<j){
            while(i<j&&re.indexOf(str[i])<0)i++;
            while(i<j&&re.indexOf(str[j])<0)j--;
            if(i<j){
                char t = str[i];
                str[i] = str[j];
                str[j] = t;
                i++;
                j--;
            }
        }
        return new String(str);
    }
}

(4)680. 验证回文串 II

/*
sign标记是否为第一次出现不相等

即不相等(1)非第一次不相等 false
       (2)第一次不相等,验证 l+1与r是否匹配,匹则过滤掉l
                        验证l与r-1是否匹配,匹则过滤掉r
                        无 false
*/
public boolean validPalindrome(String s) {
        int l=0,r=s.length()-1;
        int sign = 0;
        while(l<r){
            if(s.charAt(l)==s.charAt(r)){
                l++;
                r--;
            }
            else{
                if(sign==1)
                    return false;
                else{
                    sign = 1;
                    if(s.charAt(l+1)==s.charAt(r))
                        l++;
                    else if(s.charAt(l)==s.charAt(r-1))
                        r--;
                    else{
                        return false;
                    }
                }
            }
        }
        return true;
    }

 (5)524. 通过删除字母匹配到字典里最长单词

class Solution {
    //因为要长度最长,且长度相等时字符序最小串
    /*
    长度大于当前则直接更换
    长度与当前相等且新串序小于当前则替换(String 比较的方法compareTo())
    */
    public String findLongestWord(String s, List<String> dictionary) {
        String res = "";
        for(String str :dictionary){
            if(isSub(s,str)){
                if(str.length()>res.length()||(str.length()==res.length()&&res.compareTo(str)>0)){
                    res = str;
                }
            }
        }
        return res;

    }
    //判断是否为字串
    //t是否为s的字串:相等ti++,si++;不相等si++  最终t遍历完则是字串
    public boolean isSub(String s, String t){
        int si = 0, ti = 0;
        while(si<s.length()&&ti<t.length()){
            if(s.charAt(si)==t.charAt(ti)){
                si++;
                ti++;
            }
            else
            si++;
        }
        if(ti>=t.length())
        return true;
        return false;
    }
}

 排序

(6)215. 数组中的第K个最大元素

class Solution {
    public int findKthLargest(int[] nums, int k) {
        return findK(nums,nums.length-k,0,nums.length-1);
    }
    public int findK(int[] nums,int k, int l, int r){
        //要记录左右边界
        int el=l,er=r;
        int mid = nums[r];
        while(l<r){
            while(l<r&&nums[l]<mid) l++;
            //每次确定一个位置后,下表要改变。
            if(l<r)
            nums[r--] = nums[l];
            while(l<r&&nums[r]>mid) r--;
            if(l<r)
            nums[l++] = nums[r];
        }
        nums[l] = mid;
        if(l==k)
        return mid;
        else if(l<k)
        return findK(nums,k,l+1,er);
        else
        return findK(nums,k,el,l-1);
    }
}

(7)347. 前 K 个高频元素

class Solution {
    /*
    比较器的结构
    Comparator<T> com = new Comparator<T>(){
            public int compare(T o1,T o2){
                return 0;
            }
        };
    对于可单个控制的空用
Queue<Map.Entry<Integer,Integer>> queue = 
    new PriorityQueue<Map.Entry<Integer,Integer>>
    ((o1,o2)->(o1.getValue()-o2.getValue()));
     */
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer,Integer>  map =  new HashMap<Integer,Integer>();
        for(int i = 0;i<nums.length;i++)
        map.put(nums[i],map.getOrDefault(nums[i],0)+1);
        Comparator<Map.Entry<Integer,Integer>> com = new Comparator<Map.Entry<Integer,Integer>>(){
            public int compare(Map.Entry<Integer,Integer> o1,Map.Entry<Integer,Integer> o2){
                return o1.getValue()-o2.getValue();
            }
        };
        Queue<Map.Entry<Integer,Integer>> queue = new PriorityQueue<Map.Entry<Integer,Integer>>(com);
        for(Map.Entry<Integer,Integer> e : map.entrySet()){
            if(queue.isEmpty()||queue.size()<k)
            queue.add(e);
            else{
                if(queue.peek().getValue()<e.getValue()){
                    queue.poll();
                    queue.add(e);
                }
            }
        }
        int[] res = new int[queue.size()];
        int index = 0;
        while(!queue.isEmpty()){
            res[index++] = queue.poll().getKey();
        }
        return res;
    }
}

(8)451. 根据字符出现频率排序 

Map 和 优先队列的配合使用

class Solution {
    public String frequencySort(String s) {
        Map<Character,Integer> map = new HashMap<Character,Integer>();
        for(int i=0;i<s.length();i++){
            map.put(s.charAt(i),map.getOrDefault(s.charAt(i),0)+1);
        }
        Queue<Map.Entry<Character,Integer>> queue = new PriorityQueue<Map.Entry<Character,Integer>>((o1,o2)->(o2.getValue()-o1.getValue()));
        for(Map.Entry<Character,Integer> e:map.entrySet()){
            queue.add(e);
        }
        StringBuilder str = new StringBuilder();
        while(!queue.isEmpty()){
            Map.Entry<Character,Integer> e = queue.poll();
            char c = e.getKey();
            for(int i =0;i<e.getValue();i++){
                str.append(c);
            }
        }
        return str.toString();
    }
}

(9)75. 颜色分类

数组三区间划分

index指向当前待确定位置的元素,l指向第一个分组已有序的后一个位置,r指向已有序的前一个位置。

已全为0lr已全为2

(1)index位置元素0时,需要将其替换到 l位置,l++,因为就算交换也是前面已遍历过的元素。故替换过来的一定是1。所以index++;

(2)index位置元素为2时,需要与r位置元素交换,交换过来的为未遍历过的元素故index不变,要对此位置元素再次估算其位置

(3)index位置元素为1时,不用做任何交换。index++;

class Solution {
    public void sortColors(int[] nums) {
        int l = 0, r = nums.length-1;
        int index = 0;
        while(index<=r){
            if(nums[index]==0){
                swap(nums,index,l);
                l++;
                index++;
            }
            else if(nums[index]==2){
                swap(nums,index,r);
                r--;
            }else
                index++;
        }
    }
    public void swap(int[] nums, int a, int b){
        int t = nums[a];
        nums[a] =nums[b];
        nums[b] = t;
    }
}

 贪心算法

(10)455. 分发饼干

这里运用的思想,经过排序后,每次从饼干列表选一个最优解(当前最小可满足当前孩子胃口的饼干)

这里注意,因为经过了排序,下一个孩子胃口一定比当前大,故下次寻找饼干,直接从当前最优解下一个开始找

public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int index = 0;
        int count=0;
        for(int i = 0;i<g.length;i++){
            while(index<s.length&&s[index]<g[i]) index++;
            if(index<s.length){
                count++;
                index++;
            }
        }
        return count;
    }

(11)435. 无重叠区间

用贪心解决(计算最多可加入多少序列,总长减去最多可加入既最少可删除)

本着选择end值越小,后面就可以有更多可能加入更多的序列。

故每次用s,e更新最新加入的序列的开始与结尾,当前一个序列的开始小于当前e则说明有重叠。

   public int eraseOverlapIntervals(int[][] intervals) {
        Arrays.sort(intervals,new Comparator<int[]>(){
            public int compare(int[] o1,int[] o2){
                return o1[1]-o2[1];
            }
        });
        int count = 1;
        int s = intervals[0][0],e = intervals[0][1];
        for(int i = 1;i<intervals.length;i++){
            if(intervals[i][0]<e)
                continue;
            else{
                s = intervals[i][0];
                e = intervals[i][1];
                count++;
            }
        }
        return intervals.length-count;
    }

(12)406. 根据身高重建队列

解题思路:

在安排位置时应先安排身高高的,因为低个插入高个前不会影响高个前比他高的个数。对于身高相同的,要先安排k小的,因为k大一定在k小之后。

所以先按身高从高到低,身高相同,k从小到大排序。

一次插入队列,将元素一次插入第k个位置。因为后插的前面的元素一定都大于他,所以插在k位置可保证前面有k个值大于他。原来k位置的元素不会影响她们,因为新插入的h都比前面插入的小故不影响已插入元素前的高个个数。

具体步骤:

我们先按照身高从大到小排序(身高相同的情况下K小的在前面),这样的话,无论哪个人的身高都小于等于他前面人的身高。所以接下来只要按照K值将他插入相应的位置就可以了。
例如:示例1排完序:[[7,0],[7,1],[6,1],[5,0],[5,2],[4,4]]

新建一个一个队列:
[7,0]插入第0的位置
[7,1]插入第1的位置
[6,1]插入第1的位置,这时[7,1]就往后移一位了

class Solution {
    public int[][] reconstructQueue(int[][] people) {
        Arrays.sort(people,new Comparator<int[]>(){
            public int compare(int[] o1, int[]o2){
                return (o1[0]==o2[0])?o1[1]-o2[1]:o2[0]-o1[0];
            }
        });
        List<int[]> queue = new LinkedList<int[]>();
        for(int i=0;i<people.length;i++){
            queue.add(people[i][1],people[i]);
        }
        //注意这里如何返回数组
        return queue.toArray(new int[queue.size()][]);

    }
}
/*
toArray() 方法的语法为:

arraylist.toArray(T[] arr)
注:arraylist 是 ArrayList 类的一个对象。

参数说明:

T [] arr(可选参数)- 用于存储数组元素的数组
注意:这里 T 指的是数组的类型。

返回值

如果参数 T[] arr 作为参数传入到方法,则返回 T 类型的数组。

如果未传入参数,则返回 Object 类型的数组。
*/

(13)121. 买卖股票的最佳时机

(14)122. 买卖股票的最佳时机 II 

因为每个时间段只能持有一张股票,实际就是能将可获取收益的段加入。eg 1 ,2 ,3 (2-1+3-2=3-1)

即prices[i]-prices[i-1]>0,即该段时间可以获得收益,此段可以持有

class Solution {
    public int maxProfit(int[] prices) {
        int max = 0;
        for(int i = 1;i<prices.length;i++){
            if(prices[i]-prices[i-1]>0)
            max += prices[i]-prices[i-1]; 
        }
        return max;
    }
}

(15)605. 种花问题

用pre,next去确定是否该位置可以种花。均为0则可种

如果当前下表为0,说明前面无影响即pre为0,若下标>0则要看前一位是否为0,为了pre=0;

如果当前下表为length-1,说明后面无影响即next为0,若下标<length-1则要看后一位是否为0,为了pre=0; 

当前后均为0则此位置可以种花。将此位置置1种上花。

注意n=0情况,可能没有又个位置可种花但是n=0故也为true;

class Solution {
    public boolean canPlaceFlowers(int[] flowerbed, int n) {
        int cnt = 0;
        for(int i = 0;i<flowerbed.length;i++){
            if(flowerbed[i]!=1){
            int pre = i==0?0:flowerbed[i-1];
            int next = i==flowerbed.length-1?0:flowerbed[i+1];
            if(pre==0&&next==0){
                cnt++;
                flowerbed[i] =1;
            }
            }
            if(cnt>=n)
            return true;
        }
        return false;
}
}

(16)​​​​​​​​​​​​​​392. 判断子序列

 (17)665. 非递减数列

修改一个数的值时期非递减

当i对应值>i+1时,考虑用i+1替换i还是用i替换i+1

需要跟i-1比较,如果i+1>=i-1,应用i+1替换i

                           如果i+1<i-1,应用i替换i+1

注意对第一位进行特殊处理

class Solution {
    public boolean checkPossibility(int[] nums) {
        if(nums.length==1)
        return true;
        boolean sign = nums[0]>nums[1]?false:true;
        for(int i=1;i<nums.length-1;i++){
            if(nums[i]>nums[i+1]){
                if(sign){
                    if(nums[i+1]>=nums[i-1]){
                        nums[i]=nums[i+1];
                    }
                    else
                        nums[i+1] =nums[i];
                    sign = false;
                }
                else
                    return false;
            }
        }
        return true;
    }
}

(18)53. 最大子数组和

当sum+当前比当前还小时就应该从当前为起点重新开始算

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值