leetcode | 分类整理1

双指针:

167. 两数之和(e)

633. 两数平方和(e)

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

重点:HashSet的应用,在HashSet中查找的复杂度是O(1)

680. 回文字符串(e)

重点:因为这道题不是简单判断回文串,由于可以删一个字符(且仅能最多删一个),所以用另一个函数helper,普通的时候就一直l++,r--;第一次遇到不相等,就执行l++或者r--(删除一个字符),而且这个只会执行一次,所以直接另外写一个函数即可

88. 合并两个有序数组(e)

重点:最后

System.arraycopy的参数:(src,srcPos,des,desPos,length)

将src数组中从srcPos开始的长为length的元素复制到des数组中从desPos开始的位置。

141. 判断链表是否有环(e)

重点:一开始要判断head 和 head.next都不能为空!!!!

两种方式:while(fast != slow) 或者 while(fast != null && fast.next != null)

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

public String findLongestWord(String s, List<String> d) {
        String longestWord = "";
        for (String target : d) {
            int p1 = longestWord.length();
            int p2 = target.length();
//           longestWord.compareTo(target)即longest在target之前,不用再考虑target
            if (p1 > p2 || (p1 == p2 && longestWord.compareTo(target) < 0)) {
                continue;
            }
//            否则,判断是不是为可能的子串
            if (helper(s,target)) {
                longestWord = target;
            }
        }

        return longestWord;
    }

    private boolean helper(String s, String target) {
        int i = 0, j = 0;
        while (i < s.length() && j < target.length()) {
            if (s.charAt(i) != target.charAt(j)) {
                i++;
            }
            else {
                i++;
                j++;
            }
        }
        if (j == target.length()) {
            return true;
        }

        return false;
    }

排序:

215. 数组中第k大的元素(m)

1)快排

重点:java中Random.nextInt(bound)是用来生成一个[0,bound)之间的随机数(左闭右开)

如果使用快排,为了避免最坏的情况退化成O(n2),选择pivot的时候不应该选择nums[left],而应该随机选择

if (end > start) {
            Random random = new Random();
            int randomIndex = start + 1 + random.nextInt(end-start);
            swap(nums,start,randomIndex);
        }

2)堆排序

priorityQueue优先队列默认是一个最小堆(就是堆顶元素是最小的,所以只需要维护一个大小为k的优先队列,最后取出堆顶元素(第k大的))

347. 第k个高频元素(m)

1)堆排序:重写compare方法,实现根据map.get(key)的小顶堆(堆顶元素最小)

PriorityQueue<Integer> pq = new PriorityQueue<>(new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return map.get(o1) - map.get(o2);
    }
}
);

2)桶排序:bucket的下标就是出现的次数。用一个list数组,list[i]表示出现i次的数字们,最后倒序遍历。

List<Integer>[] bucket = new List[nums.length+1];
for (int key : map.keySet()) {
    int value = map.get(key);
    if (bucket[value] == null) {
        bucket[value] = new ArrayList<>();
    }
    bucket[value].add(key);
}

List<Integer> list = new ArrayList<>();
for (int i = bucket.length - 1; i >= 0 && list.size() < k; i--) {
    if (bucket[i] == null) {
        continue;
    }
    if (bucket[i].size() <= (k - list.size())) {
        list.addAll(bucket[i]);
    } else {
        list.addAll(bucket[i].subList(0, k - list.size()));
    }
}

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

桶排序

StringBuilder sb = new StringBuilder();
for (int i = bucket.length - 1; i >= 0; i--) {
    if (bucket[i] == null)
        continue;
    for (char c:bucket[i]
         ) {
        int j = i;
        while (j > 0) {
            sb.append(c);
            j--;
        }
    }
}

75. 颜色分类

重点:原地排序

1)两次扫描,第一次统计各个数字的个数;第二次直接重写数组

2)一次扫描,三个指针,left永远保存较小值,right永远保存较大值,还有i是当前遍历指针

//当前值==1时, cur++。不作处理.
//当前值==2时,将其和右指针的值交换,右指针--(右半部分是当前指针还未遍历到的地方,其值可能是0,1,2,所以当前cur指针不能++,当元素换过来后继续判断这个换过来的元素。)
//当前值==0时, cur++.将其和左指针交换.(左半部分是cur指针已经遍历过的,l指针其值只会是0/1)

public void sortColors(int[] nums) {
        int left = 0;
        int right = nums.length-1;
        int i = 0;
        while (i <= right) {
            if (nums[i] == 1) {
                i++;
            }
//            做完下面这个判断,left一定为0,i可能为0也可能为1
            else if (nums[i] == 0) {
                if(left!=i) {
                    int temp = nums[left];
                    nums[left] = nums[i];
                    nums[i] = temp;
                }
                i++;
                left++;
            }
//            做完下面这判断,right一定是2,而由于有半部分没有被扫描过,所以可能是1,也可能是0,也可能是2,所以i不能--
            else {
                int temp = nums[right];
                nums[right] = nums[i];
                nums[i] = temp;
                right--;
            }
        }
    }

贪心策略:

455. 分发饼干(e)

435. 无重叠子区间(m)

重写排序,先得到最多的子区间个数,然后总数减去这个值就是需要erase的

Arrays.sort(intervals, new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return o1[1] - o2[1];
    }
});

452. 用最少数量的箭弄破气球(m)

同上题,只是这题求的就是不同区间的数目

406. 根据审稿重建队列(m)

个子高的人看不到个子矮的人

核心思想:高个子先站好位,矮个子插入到K位置上,前面肯定有K个高个子,矮个子再插到前面也满足K的要求
  • 排序:
    • 按高度降序排列。
    • 在同一高度的人中,按 k 值的升序排列。
Arrays.sort(people, new Comparator<int[]>() {
    @Override
    public int compare(int[] o1, int[] o2) {
        return o1[0] != o2[0] ? (o2[0] - o1[0]) : (o1[1] - o2[1]);
    }
});
  • 逐个地把它们放在输出队列中,索引等于它们的 k 值。
for (int[] p:people
     ) {
    res.add(p[1],p);
}
  • 返回输出队列

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

主要是:改min的时候一定要改max,因为max的出现必须在min之后,

if (prices[i] > max) {
    max = prices[i];
}
else if (prices[i] < min) {
    min = prices[i];
    max = prices[i];
}
else {
    continue;
}

122. 买卖股票最佳时机(e)

和上一题不同就是可以连续买入

对于 [a, b, c, d],如果有 a <= b <= c <= d ,那么最大收益为 d - a。而 d - a = (d - c) + (c - b) + (b - a) ,因此当访问到一个 prices[i] 且 prices[i] - prices[i-1] > 0,那么就把 prices[i] - prices[i-1] 添加到收益中。

605. 种花问题(e)

53. 最大子序和(e)

655. 非递减序列(e)

数组元素个数大于3时,判断要修改哪一个数字(要么修改当前的,要么修改后一个,{4,2,3}要么修改4,要么修改2):

1. 一般修改当前数字是最好的方法,因为修改下一个数字的话,很可能影响到下下一个数字。但是,如果[3,4,2,5],当前数字是4的话,如果将4修改成2,那么你会发现,它(2)小于前一个数字3
2. 于是,我们在判断是修改当前数字还是下一个数字时,比较一下,下一个数字是否大于等于当前数字的前一个数字(nums[i+1] >= nums[i-1]),如果大于,那么即可放心修改。如果当前数字是第一个数字,即它前面没有数字的话,也是可以放心修改的。 nums[i] = nums[i+1];
5、如果下一个数字小于当前数字的前一个数字(nums[i+1] < nums[i-1]),那么将下一个数字修改成当前数字即可。 nums[i+1] = nums[i];
 

public boolean checkPossibility(int[] nums) {
        int cnt = 0;
        for (int i = 1; i < nums.length; i++) {
            if (nums[i] >= nums[i-1]) {
                continue;
            }
            cnt++;
//            {3,4,2,5}
            if (i - 2 >= 0 && nums[i-2] > nums[i]) {
                nums[i] = nums[i-1];
            }
//            4,2,3
            else {
                nums[i-1] = nums[i];
            }

        }
        return cnt <= 1;
    }

392. 判断子序列(e)

java indexOf():

  • public int indexOf(int ch): 返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。

  • public int indexOf(char ch, int fromIndex): 返回从 fromIndex 位置开始查找指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。

public boolean isSubsequence(String s, String t) {
        int i = -1;
        for (char ch:s.toCharArray()
             ) {
            i = t.indexOf(ch,i+1);
            if (i == -1) {
                return false;
            }
        }
        return true;
    }

763. 划分字母区间(m)

定义数组 last[char] 来表示字符 char 最后一次出现的下标。定义 anchor 和 j 来表示当前区间的首尾。如果遇到的字符最后一次出现的位置下标大于 j, 就让 j=last[c] 来拓展当前的区间。当遍历到了当前区间的末尾时(即 i==j ),把当前区间加入答案,同时将 start 设为 i+1 去找下一个区间。

public List<Integer> partitionLabels(String S) {
        int[] last = new int[26];
//        最后出现的位置
        for (int i = 0 ;i < S.length();i++) {
            last[S.charAt(i) - 'a'] = i;
        }

        int start = 0, end = 0;
        List<Integer> res = new ArrayList<>();
        for (int i = 0 ; i < S.length(); i++) {
            if (last[S.charAt(i) - 'a'] > end) {
                end = last[S.charAt(i) - 'a'];
            }
            if (i == end) {
                res.add(end-start+1);
                start = i + 1;
            }
        }

        return res;
    }
发布了53 篇原创文章 · 获赞 5 · 访问量 1515

猜你喜欢

转载自blog.csdn.net/zhicheshu4749/article/details/104075142