LeetCode100刷题笔记
哈希
- 两数之和
两种解法,一种双层for,算法复杂度O(n^2)
public int[] twoSum(int[] nums, int target) {
for (int i = 0; i < nums.length - 1; i++) {
for (int j = i + 1; j < nums.length; j++) {
if (nums[i] + nums[j] == target) {
return new int[]{i, j};
}
}
}
return new int[0];
}
一种是HashMap存储遍历过的值的方式,这样整体只需要遍历一次就可以找到答案了,算法复杂度O(n),用空间换时间
public int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
if (map.containsKey(target - nums[i])) {
return new int[]{map.get(target - nums[i]), i};
}
map.put(nums[i], i);
}
return new int[0];
}
- 字母异位词分组
这个是题解里面的一个解法,使用到了流操作的一些方法来解决这个问题,主要的思想是将每个单词的字母都打散,然后按照字母表的顺序重新编排,字母异位词就会被排到一起去了,其中,collect返回的结果是一个map,map的key部分是重新洗牌后的单词,而value部分则是原来的单词,所以最后需要调用values方法获得原始的单词。
public List<List<String>> groupAnagrams(String[] strs) {
return new ArrayList(Arrays.stream(strs)
.collect(Collectors.groupingBy(item -> {
char[] chars = item.toCharArray();
Arrays.sort(chars);
return new String(chars);
}))
.values());
}
- 最长连续序列
使用set先将所有的数据都存进去一下,然后对set进行遍历,判断该数字是否已经被计数,如果已经被计数过了,就不用再次计数,跳过。内层的while作用就是用来进行计数的,而外层的就是将记过数的数据跳过去的。
class Solution {
public int longestConsecutive(int[] nums) {
Set<Integer> set = new HashSet<>();
for (int num : nums) {
set.add(num);
}
int ret = 0;
for (int num : set) {
if (!set.contains(num - 1)) {
int curNum = num;
int count = 1;
while (set.contains(curNum + 1)) {
count++;
curNum++;
}
ret = Math.max(ret, count);
}
}
return ret;
}
}
双指针
- 移动零
虽然,但是,这道题使用一个index指针就够了,复杂度O(n)
class Solution {
public void moveZeroes(int[] nums) {
int index = 0;
for (int num : nums) {
if (num != 0) {
nums[index++] = num;
}
}
for (int i = index; i < nums.length; i++) {
nums[i] = 0;
}
}
}
- 盛最多水的容器
双指针方式解决,双指针指向左右两边的柱子下标,下标相减就是容器的“宽度”,两根柱子中小的哪一根就会成为容器容纳量的瓶颈。容器的容量由“高度”和“宽度”两部分组成,两部分的最佳比例就是我们要找的目标,并且容器的“高度”和“宽度”之间还有一定的对应关系,所以,我们解决这个问题的时候思路上就可以想办法将一个量作为标准,让这个量缓慢变化,而同时尽量使另一个量达到最优的结果,遍历所有这两个量的组合,算出里面最好的一种组合,然后作为结果返回即可。
class Solution {
public int maxArea(int[] height) {
// 下标相减就是容器的“宽度”,“高度”就是数组元素的大小
int left = 0;
int right = height.length - 1;
int ret = 0;
while (left < right) {
ret = Math.max((right - left) * Math.min(height[left], height[right]), ret);
if (height[left] < height[right]) {
left++;
} else {
right--;
}
}
return ret;
}
}
- 三数之和
这道题的重点在于去重,下面这种解法按照我的理解就是三重的去重操作,第一重是对于第一个选择的数字去重,然后是对于第二个,第三个
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> ret = new ArrayList<>();
if (nums.length < 3) {
return ret;
}
Arrays.sort(nums);
for (int i = 0; i < nums.length; i++) {
if (nums[i] > 0) {
break;
}
if (i != 0 && nums[i - 1] == nums[i]) {
continue;
}
int left = i + 1;
int right = nums.length - 1;
while (left < right) {
if (nums[i] + nums[left] + nums[right] == 0) {
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[left]);
list.add(nums[right]);
ret.add(list);
while (left < right && nums[left] == nums[++left]);
while (left < right && nums[right] == nums[--right]);
} else if (nums[i] + nums[left] + nums[right] < 0) {
while (left < right && nums[left] == nums[++left]);
} else {
while (left < right && nums[right] == nums[--right]);
}
}
}
return ret;
}
}
- 接雨水
单调栈,满足大于栈顶的就有可能接水,否则,放进去。
class Solution {
public int trap(int[] height) {
if (height == null) {
return 0;
}
Stack<Integer> stack = new Stack<>();
int ret = 0;
for (int i = 0; i < height.length; i++) {
while (!stack.empty() && height[stack.peek()] < height[i]) {
int curIndex = stack.pop();
while (!stack.empty() && height[curIndex] == height[stack.peek()]) {
stack.pop();
}
if (!stack.empty()) {
int stackTop = stack.peek();
ret += (i - stackTop - 1) * (Math.min(height[stackTop] - height[curIndex], height[i] - height[curIndex]));
}
}
stack.push(i);
}
return ret;
}
}
滑动窗口
- 无重复字符的最长子串
class Solution {
public int lengthOfLongestSubstring(String s) {
int l = 0;
int r = 0;
int ret = 0;
Set<Character> set = new HashSet<>();
while (r < s.length()) {
if (!set.contains(s.charAt(r))) {
set.add(s.charAt(r));
ret = Math.max(ret, r - l + 1);
r++;
} else {
set.remove(s.charAt(l));
l++;
}
}
return ret;
}
}
- 找到字符串中所有字母异位词
这道题的解法重点在下面的for循环中,上面的for只是将“模板单词”包含的字母数量进行记录,而重点来了,下面的那个for遍历所有的s字符串中的字母,利用“模板单词”的长度与要在s字符串中找到的异位词子串间的关系,将整道题的解法变得十分奇妙,判断是否匹配到异位词只需要判断滑动窗口的长度是否满足条件,这样做的前提是前面将s字符串滑动串口中的单词数量统计到一个数组中去后,对数组相应位置的数量判断是否满足要求,不满足则进行调整。
class Solution {
public List<Integer> findAnagrams(String s, String p) {
List<Integer> ret = new ArrayList<>();
int n = s.length();
int m = p.length();
if (n < m) {
return ret;
}
int[] sCut = new int[26];
int[] pCut = new int[26];
for (int i = 0; i < m; i++) {
pCut[p.charAt(i) - 'a']++;
}
int left = 0;
for (int right = 0; right < n; right++) {
int curRight = s.charAt(right) - 'a';
sCut[curRight]++;
while (sCut[curRight] > pCut[curRight]) {
sCut[s.charAt(left) - 'a']--;
left++;
}
if (right - left + 1 == m) {
ret.add(left);
}
}
return ret;
}
}

浙公网安备 33010602011771号