三数之和
题目链接:三数之和
个人版本一(排序处理)
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
Arrays.sort(nums);
List<List<Integer>> resultList = new ArrayList<>();
HashSet<List<Integer>> s = new HashSet<>();
if(nums.length < 3){
return resultList;
}
int i = 0, j = nums.length-1, tmpI, tmp, start, end;
// 排序后整体符合的情况
if((nums[i] > 0 && nums[j] > 0) || (nums[i] < 0 && nums[j] < 0)){
return resultList;
}
// 排序后为全0的情况
if(nums[i] == 0 && nums[j] == 0){
List<Integer> l1 = new ArrayList<>();
l1.add(0);l1.add(0);l1.add(0);
resultList.add(l1);
return resultList;
}
// 处理大量重复后缀
end = nums[j];
tmpI = j;
while (nums[--tmpI] == end);
end = j-tmpI>=2?tmpI+2:tmpI+1;
if(j - tmpI >= 3 && nums[j] == 0){
List<Integer> l1 = new ArrayList<>();
l1.add(0);l1.add(0);l1.add(0);
s.add(l1);
}
while (end-i >= 2){
// 处理大量重复前缀
start = nums[i];
tmpI = i;
while (nums[++tmpI] == start);
if(tmpI - i >= 3 && nums[i+1] == 0){
List<Integer> l1 = new ArrayList<>();
l1.add(0);l1.add(0);l1.add(0);
s.add(l1);
}
i = tmpI-i>=2?tmpI-2:tmpI-1;
j = end;
if((nums[i] > 0 && nums[j] > 0) || (nums[i] < 0 && nums[j] < 0)){
break;
}
while (j-i >= 2){
if((nums[i] > 0 && nums[j] > 0) || (nums[i] < 0 && nums[j] < 0)){
break;
}
tmpI = i+1;
tmp = nums[i] + nums[j];
tmp = -1*tmp;
while (tmpI < j && tmp >= nums[tmpI]){
if(nums[tmpI] == tmp){
List<Integer> l1 = new ArrayList<>();
l1.add(nums[i]);l1.add(nums[tmpI]);l1.add(nums[j]);
s.add(l1);
}
tmpI++;
}
j--;
}
i++;
}
for(List<Integer> l1: s){
resultList.add(l1);
}
return resultList;
}
}
个人版本二(三数之和降为两数之和)
class Solution {
public HashSet<List<Integer>> set = new HashSet<>();
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> resultList = new ArrayList<>();
if(nums.length < 3){
return resultList;
}
int tmpI, end, endI;
end = nums[nums.length-1];
// 处理冗余后缀冗余元素
tmpI = nums.length-1;
while (tmpI > 2 && nums[--tmpI] == end);
endI = nums.length-1;
// 后缀大于等于3
if(nums.length-1-tmpI >= 3){
endI = tmpI+3;
}
for(int i=0 ; i<=endI-2; i++){
// 前缀冗余元素
end = nums[i];
tmpI = i;
while (tmpI < endI-2 && nums[++tmpI] == end);
if(tmpI - i >= 3){
i = tmpI-3;
}
if(i < endI){
// 将三数之和问题转换成两数之和的问题
twoSum(nums, -1*nums[i], i+1, endI);
}else{
if(nums[i] == 0){
List<Integer> l = new ArrayList<>();
Collections.addAll(l, 0, 0, 0);
Collections.sort(l);
set.add(l);
}
}
}
for(List<Integer> l: set){
resultList.add(l);
}
return resultList;
}
public void twoSum(int[] nums, int target, int start, int end) {
Map<Integer, Integer> map = new HashMap<>();
for(int i = start; i <= end; i++) {
int key = target - nums[i];
if(map.containsKey(key) && map.get(key) == 0) {
List<Integer> l = new ArrayList<>();
Collections.addAll(l, -1*target, key, nums[i]);
Collections.sort(l);
if(!set.contains(l)){
set.add(l);
}
map.put(nums[i], 1);
map.put(key, 1);
}else{
map.put(nums[i], 0);
}
}
}
}
官方版本一(排序和双指针)
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
int n = nums.length;
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<List<Integer>>();
// 枚举 a
for (int first = 0; first < n; ++first) {
// 需要和上一次枚举的数不相同
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
// c 对应的指针初始指向数组的最右端
int third = n - 1;
int target = -nums[first];
// 枚举 b
for (int second = first + 1; second < n; ++second) {
// 需要和上一次枚举的数不相同
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
// 需要保证 b 的指针在 c 的指针的左侧
while (second < third && nums[second] + nums[third] > target) {
--third;
}
// 如果指针重合,随着 b 后续的增加
// 就不会有满足 a+b+c=0 并且 b<c 的 c 了,可以退出循环
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
List<Integer> list = new ArrayList<Integer>();
list.add(nums[first]);
list.add(nums[second]);
list.add(nums[third]);
ans.add(list);
}
}
}
return ans;
}
}
其他版本一(排序和双指针)
class Solution {
//定义三个指针,保证遍历数组中的每一个结果
//画图,解答
public List<List<Integer>> threeSum(int[] nums) {
//定义一个结果集
List<List<Integer>> res = new ArrayList<>();
//数组的长度
int len = nums.length;
//当前数组的长度为空,或者长度小于3时,直接退出
if(nums == null || len <3){
return res;
}
//将数组进行排序
Arrays.sort(nums);
//遍历数组中的每一个元素
for(int i = 0; i<len;i++){
//如果遍历的起始元素大于0,就直接退出
//原因,此时数组为有序的数组,最小的数都大于0了,三数之和肯定大于0
if(nums[i]>0){
break;
}
//去重,当起始的值等于前一个元素,那么得到的结果将会和前一次相同
if(i > 0 && nums[i] == nums[i-1]) continue;
int l = i +1;
int r = len-1;
//当 l 不等于 r时就继续遍历
while(l<r){
//将三数进行相加
int sum = nums[i] + nums[l] + nums[r];
//如果等于0,将结果对应的索引位置的值加入结果集中
if(sum==0){
// 将三数的结果集加入到结果集中
res.add(Arrays.asList(nums[i], nums[l], nums[r]));
//在将左指针和右指针移动的时候,先对左右指针的值,进行判断
//如果重复,直接跳过。
//去重,因为 i 不变,当此时 l取的数的值与前一个数相同,所以不用在计算,直接跳
while(l < r && nums[l] == nums[l+1]) {
l++;
}
//去重,因为 i不变,当此时 r 取的数的值与前一个相同,所以不用在计算
while(l< r && nums[r] == nums[r-1]){
r--;
}
//将 左指针右移,将右指针左移。
l++;
r--;
//如果结果小于0,将左指针右移
}else if(sum < 0){
l++;
//如果结果大于0,将右指针左移
}else if(sum > 0){
r--;
}
}
}
return res;
}
}
最接近的三数之和
题目链接:最接近的三数之和
个人版本一(排序加双指针)
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int resultInt = -1, l, r, sum, sum1 = Integer.MAX_VALUE, cha1, cha2, resultCha = Integer.MAX_VALUE;
sum = nums[0]+nums[1]+nums[2];
// 刚好是3
if(nums.length == 3){
return sum;
}
// 最小的都比target大
if(sum >= target){
return sum;
}
// 最大的都比target小
r = nums.length-1;
sum = nums[r]+nums[r-1]+nums[r-2];
if(sum <= target){
return sum;
}
boolean isRight = true;
sum = nums[0]+nums[1]+nums[nums.length-1];
if(sum > target){
isRight = true;
}else if(sum < target){
isRight = false;
}
for(int i=0 ; i<nums.length ; i++){
if(i>0 && nums[i] == nums[i-1]) continue;
r = nums.length-1;
l = i+1;
while (l<r){
sum = nums[l]+nums[r]+nums[i];
if(sum > target){
if(!isRight){
cha1 = Math.abs(target - sum);
cha2 = Math.abs(target - sum1);
if(cha1 <= cha2){
if(cha1 < resultCha){
resultCha = cha1;
resultInt = sum;
}
}else{
if(cha2 < resultCha){
resultCha = cha2;
resultInt = sum1;
}
}
}
r--;
isRight = true;
}else if(sum < target){
if(isRight){
cha1 = Math.abs(target - sum);
cha2 = Math.abs(target - sum1);
if(cha1 <= cha2){
if(cha1 < resultCha){
resultCha = cha1;
resultInt = sum;
}
}else{
if(cha2 < resultCha){
resultCha = cha2;
resultInt = sum1;
}
}
}
l++;
isRight = false;
}else{
return target;
}
sum1 = sum;
}
}
return resultInt;
}
}
官方版本一(排序加双指针)
class Solution {
public int threeSumClosest(int[] nums, int target) {
Arrays.sort(nums);
int n = nums.length;
int best = 10000000;
// 枚举 a
for (int i = 0; i < n; ++i) {
// 保证和上一次枚举的元素不相等
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
// 使用双指针枚举 b 和 c
int j = i + 1, k = n - 1;
while (j < k) {
int sum = nums[i] + nums[j] + nums[k];
// 如果和为 target 直接返回答案
if (sum == target) {
return target;
}
// 根据差值的绝对值来更新答案
if (Math.abs(sum - target) < Math.abs(best - target)) {
best = sum;
}
if (sum > target) {
// 如果和大于 target,移动 c 对应的指针
int k0 = k - 1;
// 移动到下一个不相等的元素
while (j < k0 && nums[k0] == nums[k]) {
--k0;
}
k = k0;
} else {
// 如果和小于 target,移动 b 对应的指针
int j0 = j + 1;
// 移动到下一个不相等的元素
while (j0 < k && nums[j0] == nums[j]) {
++j0;
}
j = j0;
}
}
}
return best;
}
}
电话号码的字母组合
题目链接:电话号码的字母组合
个人版本一(复用)
class Solution {
public List<String> letterCombinations(String digits) {
List<String> list = new ArrayList<>();
if(digits == null || digits.length() == 0){
return list;
}
Map<String, String> table = new HashMap<String, String>(){{
put("2", "abc");put("3", "def");put("4", "ghi");put("5", "jkl");put("6", "mno");
put("7", "pqrs");put("8", "tuv");put("9", "wxyz");
}};
String[] dArr = digits.split("");
if(dArr.length == 1){
return Arrays.asList(table.get(digits).split(""));
}
// 存储当前遍历集合
List<String> dList = new ArrayList<>();
for(String s: dArr){
dList.add(table.get(s));
}
list = Arrays.asList(dList.get(0).split(""));
int i;
int size = dList.size();
for( i=1 ; i< size ; i++){
list = getGroup(list, Arrays.asList(dList.get(i).split("")));
}
return list;
}
// 获取两个字符的组合
public List<String> getGroup(List<String> l1, List<String> l2){
List<String> list = new ArrayList<>();
for(int i=0 ; i<l1.size() ; i++){
for(int j=0 ; j<l2.size() ; j++){
list.add(l1.get(i)+l2.get(j));
}
}
return list;
}
}
官方版本一(回溯)
class Solution {
public List<String> letterCombinations(String digits) {
List<String> combinations = new ArrayList<String>();
if (digits.length() == 0) {
return combinations;
}
Map<Character, String> phoneMap = new HashMap<Character, String>() {{
put('2', "abc");
put('3', "def");
put('4', "ghi");
put('5', "jkl");
put('6', "mno");
put('7', "pqrs");
put('8', "tuv");
put('9', "wxyz");
}};
backtrack(combinations, phoneMap, digits, 0, new StringBuffer());
return combinations;
}
public void backtrack(List<String> combinations, Map<Character, String> phoneMap, String digits, int index, StringBuffer combination) {
if (index == digits.length()) {
combinations.add(combination.toString());
} else {
char digit = digits.charAt(index);
String letters = phoneMap.get(digit);
int lettersCount = letters.length();
for (int i = 0; i < lettersCount; i++) {
combination.append(letters.charAt(i));
backtrack(combinations, phoneMap, digits, index + 1, combination);
combination.deleteCharAt(index);
}
}
}
}
四数之和
题目链接:四数之和
个人版本一
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> list = new ArrayList<>();
if(nums.length < 4){
return list;
}
Arrays.sort(nums);
int l1, l2, r1, r2, sum;
for(l1=0 ; l1<nums.length-3 ; l1++){
if (l1>0 && nums[l1] == nums[l1-1]) continue;;
for(l2 = l1+1 ; l2< nums.length-2 ; l2++){
if (l2>l1+1 && nums[l2] == nums[l2-1]) continue;
r1 = l2+1;
r2 = nums.length-1;
while (r1<r2){
// 溢出判断
int left = nums[l1]+nums[l2];
int right = nums[r1]+nums[r2];
if(left > 0){
int cha = Integer.MAX_VALUE-left;
if(cha < right){
r1++;
continue;
}
}
if(right < 0){
int cha = Integer.MIN_VALUE-right;
if(cha > left){
r2--;
continue;
}
}
sum = nums[l1]+nums[l2]+nums[r1]+nums[r2];
if(sum == target){
list.add(Arrays.asList(nums[l1], nums[l2], nums[r1], nums[r2]));
while (r1<r2 && nums[r1]==nums[r1+1]){
r1++;
}
while (r1<r2 && nums[r2]==nums[r2-1]){
r2--;
}
r1++;
r2--;
}else if(sum < target){
r1++;
}else {
r2--;
}
}
}
}
return list;
}
}
官方版本一
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> quadruplets = new ArrayList<List<Integer>>();
if (nums == null || nums.length < 4) {
return quadruplets;
}
Arrays.sort(nums);
int length = nums.length;
for (int i = 0; i < length - 3; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {
continue;
}
if ((long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
break;
}
if ((long) nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
for (int j = i + 1; j < length - 2; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) {
continue;
}
if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
break;
}
if ((long) nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
int left = j + 1, right = length - 1;
while (left < right) {
int sum = nums[i] + nums[j] + nums[left] + nums[right];
if (sum == target) {
quadruplets.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
while (left < right && nums[left] == nums[left + 1]) {
left++;
}
left++;
while (left < right && nums[right] == nums[right - 1]) {
right--;
}
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
}
return quadruplets;
}
}
删除链表的倒数第 N 个结点
题目链接:删除链表的倒数第 N 个结点
个人版本一
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode listNode = head, tmpListNode = head;
int count = 0;
while (tmpListNode != null){
if(count > n){
listNode = listNode.next;
}
count++;
tmpListNode = tmpListNode.next;
}
// 删除头结点情况
if(count == n){
return head.next;
}
listNode.next = listNode.next.next;
return head;
}
}
### 其他版本一
```java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
// 双指针辅助定位,设总共m节点;
// 将sec定位到倒数第(n + 1)个,就是第m - n个;
// sec = 0 -> m - n,即fir和sec同步前移的节点数为m - n,则fir先行前移m - (m - n)个;
ListNode dummy = new ListNode(-1, head);
ListNode first = dummy;
ListNode second = dummy;
// fir先行前移n个节点;
while (n > 0) {
first = first.next;
n--;
}
// fir和sec同步前移m - n个;
while (first.next != null) {
first = first.next;
second = second.next;
}
// 删除第m - n + 1个(倒数第n个)节点
second.next = second.next.next;
return dummy.next;
}
}
官方版本一(计算长度)
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0, head);
int length = getLength(head);
ListNode cur = dummy;
for (int i = 1; i < length - n + 1; ++i) {
cur = cur.next;
}
cur.next = cur.next.next;
ListNode ans = dummy.next;
return ans;
}
public int getLength(ListNode head) {
int length = 0;
while (head != null) {
++length;
head = head.next;
}
return length;
}
}
官方版本二(栈实现)
class Solution {
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0, head);
Deque<ListNode> stack = new LinkedList<ListNode>();
ListNode cur = dummy;
while (cur != null) {
stack.push(cur);
cur = cur.next;
}
for (int i = 0; i < n; ++i) {
stack.pop();
}
ListNode prev = stack.peek();
prev.next = prev.next.next;
ListNode ans = dummy.next;
return ans;
}
}
有效的括号
个人版本一
class Solution {
public boolean isValid(String s) {
if(s.length()%2 != 0){
return false;
}
Map<Character, Character> table = new HashMap<Character, Character>(){{
put(')', '(');
put('}', '{');
put(']', '[');
put('(', ' ');
put('{', ' ');
put('[', ' ');
}};
Deque<Character> deque = new LinkedList<>();
for(int i=0 ; i<s.length() ; i++){
char c1 = s.charAt(i);
if(!deque.isEmpty()){
char c2 = deque.peek();
if(c2 == table.get(c1)){
deque.pop();
}else{
deque.push(c1);
}
}else{
deque.push(c1);
}
}
return deque.isEmpty()?true:false;
}
}
其他版本一
class Solution {
private static final Map<Character,Character> map = new HashMap<Character,Character>(){{
put('{','}'); put('[',']'); put('(',')'); put('?','?');
}};
public boolean isValid(String s) {
if(s.length() > 0 && !map.containsKey(s.charAt(0))) return false;
LinkedList<Character> stack = new LinkedList<Character>() {{ add('?'); }};
for(Character c : s.toCharArray()){
if(map.containsKey(c)) stack.addLast(c);
else if(map.get(stack.removeLast()) != c) return false;
}
return stack.size() == 1;
}
}
官方版本一
class Solution {
public boolean isValid(String s) {
int n = s.length();
if (n % 2 == 1) {
return false;
}
Map<Character, Character> pairs = new HashMap<Character, Character>() {{
put(')', '(');
put(']', '[');
put('}', '{');
}};
Deque<Character> stack = new LinkedList<Character>();
for (int i = 0; i < n; i++) {
char ch = s.charAt(i);
if (pairs.containsKey(ch)) {
if (stack.isEmpty() || stack.peek() != pairs.get(ch)) {
return false;
}
stack.pop();
} else {
stack.push(ch);
}
}
return stack.isEmpty();
}
}
合并两个有序链表
题目链接:合并两个有序链表
个人版本一
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode mergeTwoLists(ListNode list1, ListNode list2) {
ListNode l1 = list1, l2 = list2, tmpNode;
ListNode head = new ListNode(), tail = head;
while (l1 != null && l2 != null){
if(l1.val <= l2.val){
tmpNode = new ListNode(l1.val);
tail.next = tmpNode;
l1 = l1.next;
}else if(l1.val > l2.val){
tmpNode = new ListNode(l2.val);
tail.next = tmpNode;
l2 = l2.next;
}
tail = tail.next;
}
if(l1 != null){
tail.next = l1;
}
if(l2 != null){
tail.next = l2;
}
return head.next;
}
}
官方版本一(递归)
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1 == null) {
return l2;
} else if (l2 == null) {
return l1;
} else if (l1.val < l2.val) {
l1.next = mergeTwoLists(l1.next, l2);
return l1;
} else {
l2.next = mergeTwoLists(l1, l2.next);
return l2;
}
}
}
官方版本二(迭代)
class Solution {
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode prehead = new ListNode(-1);
ListNode prev = prehead;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) {
prev.next = l1;
l1 = l1.next;
} else {
prev.next = l2;
l2 = l2.next;
}
prev = prev.next;
}
// 合并后 l1 和 l2 最多只有一个还未被合并完,我们直接将链表末尾指向未合并完的链表即可
prev.next = l1 == null ? l2 : l1;
return prehead.next;
}
}