LeetCode Hot100
3. 无重复字符的最长子串
- 算法:滑动窗口法
- 窗口存放[left, right)中字符的数量
public int lengthOfLongestSubstring(String s) {
int left = 0;
int right = 0;
Map<Character, Integer> windows = new HashMap<>();
int maxVal = 0;
while(right < s.length()){
char c = s.charAt(right);
windows.put(c, windows.getOrDefault(c, 0) + 1);
right ++;
while(windows.get(c) > 1){
char d = s.charAt(left);
windows.put(d, windows.get(d) - 1);
left ++;
}
maxVal = Integer.max(maxVal, right - left);
}
return maxVal;
}
- 优化版
- left不需要一个一个滑动,map存放的是下标,但是容易出错
public int lengthOfLongestSubstring(String s) {
int left = 0;
int right = 0;
Map<Character, Integer> windows = new HashMap<>();
int maxVal = 0;
while(right < s.length()){
char c = s.charAt(right);
if(windows.containsKey(c) && windows.get(c) >= left){
maxVal = Integer.max(maxVal, right - left);
left = windows.get(c) + 1;
}
windows.put(c, right);
right ++;
}
maxVal = Integer.max(maxVal, right - left);
return maxVal;
}
5. >最长回文子串
- 解法:中心扩列法
- 注意:substring需要的是左右的下标
public String longestPalindrome(String s) {
int left = 0;
int maxLen = 1;
for(int i = 0;i < s.length();i ++){
int len1 = subLongestPalindrome(s, i , i);
int len2 = subLongestPalindrome(s, i , i + 1);
int subMax = Integer.max(len1, len2);
if(subMax > maxLen){
left = i - (subMax - 1) / 2;
maxLen = subMax;
}
}
return s.substring(left, left + maxLen);
}
private int subLongestPalindrome(String s, int left, int right){
int maxLen = 0;
while(left >= 0 && right < s.length()){
if(s.charAt(left) == s.charAt(right)){
maxLen = Integer.max(maxLen, right - left + 1);
left --;
right ++;
}else {
return maxLen;
}
}
return maxLen;
}
11. >盛最多水的容器
- 双指针
public int maxArea(int[] height) {
int max = 0;
int left = 0;
int right = height.length - 1;
while(left < right){
max = Integer.max(max, Integer.min(height[left], height[right]) * (right - left));
if(height[left] < height[right]){
left ++;
}else {
right --;
}
}
return max;
}
15. >三数之和
- 三指针
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<>();
for(int i = 0;i < nums.length;i ++){
int left = i + 1;
int right = nums.length - 1;
// 去重
if(i > 0 && nums[i] == nums[i - 1]){
continue;
}
while(left < right){
int sum = nums[left] + nums[right] + nums[i];
if(sum == 0){
ans.add(Arrays.asList(nums[left], nums[right], nums[i]));
left ++;
right --;
// 去重
while(left < right && nums[left] == nums[left - 1]) left ++;
while(left < right && nums[right] == nums[right + 1]) right --;
}else if(sum < 0){
left ++;
}else {
right --;
}
}
}
return ans;
}
17. >电话号码的字母组合
- 算法:回溯法
组合和排列一般都会用到回溯法,排列和组合的区别:组合不考虑顺序,例如对[A,B]选两个数进行排列组合,[A,B]即组合成一组,而排列考虑顺序,[A,B]、[B,A]为不同排列。
public List<String> letterCombinations(String digits) {
if(digits == null || digits.length() == 0){
return new ArrayList<>();
}
Map<Character, String> map = new HashMap<>();
map.put('2', "abc");
map.put('3', "def");
map.put('4', "ghi");
map.put('5', "jkl");
map.put('6', "mno");
map.put('7', "pqrs");
map.put('8', "tuv");
map.put('9', "wxyz");
List<String> ans = new ArrayList<>();
backtract(digits, new StringBuilder(), ans, map, 0);
return ans;
}
public void backtract(String digits, StringBuilder subAns, List<String> ans, Map<Character, String> map, int index){
if(subAns.length() == digits.length()){
ans.add(new String(subAns));
return;
}
char c = digits.charAt(index);
String nums = map.get(c);
for(int i = 0;i < nums.length();i ++){
char c2 = nums.charAt(i);
subAns.append(c2);
backtract(digits, subAns, ans, map, index + 1);
subAns.deleteCharAt(subAns.length() - 1);
}
}
19. 删除链表的倒数第 N 个结点
- 算法:快慢指针
- 注意:添加dummyHead
public ListNode removeNthFromEnd(ListNode head, int n) {
if(head == null || n <= 0){
return head;
}
ListNode dummyHead = new ListNode();
dummyHead.next = head;
ListNode p1 = dummyHead;
ListNode p2 = dummyHead;
for(int i = 1;i <= n;i ++){
p1 = p1.next;
}
while(p1.next != null){
p1 = p1.next;
p2 = p2.next;
}
p2.next = p2.next.next;
return dummyHead.next;
}
20. >有效的括号
- 算法:利用栈
- 遇到左符合则入栈
- 遇到右符合则检查栈不为空且栈顶元素需为其左符号
public boolean isValid(String s) {
Deque<Character> stack = new ArrayDeque<>();
Map<Character, Character> map = new HashMap<>();
map.put('(', ')');
map.put('[', ']');
map.put('{', '}');
for(char c : s.toCharArray()){
if(map.containsKey(c)){
stack.push(c);
}else {
if(stack.isEmpty() || map.get(stack.peek()) != c){
return false;
}
stack.pop();
}
}
return stack.isEmpty();
}
21. 合并两个有序链表
- 思路:归并排序
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode dummyHead = new ListNode();
ListNode p3 = dummyHead;
ListNode p1 = list1;
ListNode p2 = list2;
while(p1 != null && p2 != null){
if(p1.val < p2.val){
p3.next = p1;
p1 = p1.next;;
}else {
p3.next = p2;
p2 = p2.next;;
}
p3 = p3.next;
}
while(p1 != null){
p3.next = p1;
p1 = p1.next;
p3 = p3.next;
}
while(p2 != null){
p3.next = p2;
p2 = p2.next;
p3 = p3.next;
}
return dummyHead.next;
}
22. 括号生成
- 算法:回溯法(全排列) - 暴力解法
public List<String> generateParenthesis(int n) {
List<String> ans = new ArrayList<>();
backtract(ans, new StringBuilder(), n, n);
return ans;
}
public void backtract(List<String> ans, StringBuilder subAns, int left, int right){
if(left == 0 && right == 0){
String str = new String(subAns);
if(valid(str)) ans.add(str);
return;
}
if(left > 0){
subAns.append("(");
backtract(ans, subAns, left - 1, right);
subAns.deleteCharAt(subAns.length() - 1);
}
if(right > 0){
subAns.append(")");
backtract(ans, subAns, left, right - 1);
subAns.deleteCharAt(subAns.length() - 1);
}
}
private boolean valid(String subAns){
int cnt = 0;
for(char c : subAns.toCharArray()){
if(c == '('){
cnt ++;
}else {
if(cnt > 0){
cnt --;
}else {
return false;
}
}
}
return cnt == 0;
}
- 最优:优化后
public List<String> generateParenthesis(int n) {
List<String> ans = new ArrayList<>();
backtract(ans, new StringBuilder(), n, n);
return ans;
}
public void backtract(List<String> ans, StringBuilder subAns, int left, int right){
if(left == 0 && right == 0){
ans.add(new String(subAns));
return;
}
if(left > 0){
subAns.append("(");
backtract(ans, subAns, left - 1, right);
subAns.deleteCharAt(subAns.length() - 1);
}
// 关键点
if(right > left){
subAns.append(")");
backtract(ans, subAns, left, right - 1);
subAns.deleteCharAt(subAns.length() - 1);
}
}