目录
【写在前面】
前文参考:LeetCode代码刷题(9~16)
17. 电话号码的字母组合
题目:
给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合。答案可以按 任意顺序 返回。给出数字到字母的映射如下(与电话按键相同)。注意 1 不对应任何字母。
示例 1:
输入:digits = "23"
输出:["ad","ae","af","bd","be","bf","cd","ce","cf"]
示例 2:输入:digits = ""
输出:[]
示例 3:输入:digits = "2"
输出:["a","b","c"]
提示:
0 <= digits.length <= 4
digits[i] 是范围 ['2', '9'] 的一个数字。
代码:
package com.my.test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class letterCombinations {
public static void main(String[] args) {
String digits = "267";
List<String> result = letterCombinations(digits);
System.out.println("数字字符串"+digits+"所能表示的字母组合为:");
System.out.print("[");
for(int i=0; i<result.size(); i++){
if(i == result.size()-1){
System.out.print(result.get(i));
} else {
System.out.print(result.get(i) + ",");
}
}
System.out.println("]");
System.out.println("一共有"+result.size()+"种组合。");
}
public static List<String> letterCombinations(String digits){
List<String> result = new ArrayList<>();
if(digits == null && digits.length() == 0){
return result;
}
Map<String, char[]> phoneMap = new HashMap<>();
phoneMap.put("2", new char[]{'a', 'b', 'c'});
phoneMap.put("3", new char[]{'d', 'e', 'f'});
phoneMap.put("4", new char[]{'g', 'h', 'i'});
phoneMap.put("5", new char[]{'j', 'k', 'l'});
phoneMap.put("6", new char[]{'m', 'n', 'o'});
phoneMap.put("7", new char[]{'p', 'q', 'r', 's'});
phoneMap.put("8", new char[]{'t', 'u', 'v'});
phoneMap.put("9", new char[]{'w', 'x', 'y', 'z'});
backTrack(result, phoneMap, digits, 0, new StringBuffer());
return result;
}
public static void backTrack(List<String> combinations, Map<String, char[]> phoneMap, String digits, int index, StringBuffer combination){
if(index == digits.length()){ //递归退出或结束条件。 递归中重要的一个条件,不然无法结束递归
combinations.add(combination.toString());
} else {
String digit = digits.substring(index, index+1);
char[] letters = phoneMap.get(digit);
for(char letter: letters){
combination.append(letter);
backTrack(combinations, phoneMap, digits, index+1, combination); //递归
//重要!结束上面递归之后,去掉组合里的最后一位,进入下一轮循环。比如"23"的组合,上面的递归得出ad之后,到这一步,combination中去掉d,进入下一轮循环ae的情况
combination.deleteCharAt(index);
}
}
}
}
输出:
数字字符串267所能表示的字母组合为:
[amp,amq,amr,ams,anp,anq,anr,ans,aop,aoq,aor,aos,bmp,bmq,bmr,bms,bnp,bnq,bnr,bns,bop,boq,bor,bos,cmp,cmq,cmr,cms,cnp,cnq,cnr,cns,cop,coq,cor,cos]
一共有36种组合。Process finished with exit code 0
18. 四数之和
题目:
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案 。示例 1:
输入:nums = [1,0,-1,0,-2,2], target = 0
输出:[[-2,-1,1,2],[-2,0,0,2],[-1,0,0,1]]
示例 2:输入:nums = [2,2,2,2,2], target = 8
输出:[[2,2,2,2]]
提示:
1 <= nums.length <= 200
-109 <= nums[i] <= 109
-109 <= target <= 109
代码:
package com.my.test;
import java.util.*;
public class fourSum {
public static void main(String[] args) {
System.out.println("待检查的数组为:");
System.out.print("[");
int[] array = {1,0,-1,0,-2,2};
for(int i=0; i<array.length; i++){
if(i==array.length-1){
System.out.print(array[i]);
} else {
System.out.print(array[i]+",");
}
}
System.out.println("]");
int target = 0;
System.out.println("目标值为:"+target);
System.out.println("原始数组中,满足条件的四元组为:");
System.out.print("[");
List<List<Integer>> result = fourSum(array, target);
for (int j=0; j<result.size(); j++){
if(j==result.size()-1){
System.out.print(result.get(j));
} else {
System.out.print(result.get(j) + ",");
}
}
System.out.println("]");
}
public static List<List<Integer>> fourSum(int[] nums, int target){
//数组排序,升序
Arrays.sort(nums);
//数组长度
int l = nums.length;
// 定义Set集合,集合里放多个List(结果).
// 利用Set去重的特性,确保里面保存的多个结果List不重复
Set<List<Integer>> hashSet = new HashSet<>();
for(int i=0; i<l; i++){
//去重,使这次的数和上一次的数不同
if(i>0 && nums[i] == nums[i-1]){
continue;
}
//遍历数组
for(int j=i+1; j<l; j++){
//固定nums[j]为第j个,然后从第j+1到末尾的多个数中,逐个比对,找出符合条件的
int left = j+1;
int right = l-1;
//去重
if(j>i+1 && nums[j] == nums[j-1]){
continue;
}
while(left < right){
int sum = nums[i] + nums[j] +nums[left] + nums[right];
if(sum == target){ //如果sum==target, 即找到符合“4数之和等于目标值”的情况,则将4个数存到List, 然后添加到集合Set中
List<Integer> list = new ArrayList<>();
list.add(nums[i]);
list.add(nums[j]);
list.add(nums[left]);
list.add(nums[right]);
hashSet.add(list);
//去重
while (left<right && nums[left]==nums[left+1]){
left++;
}
while (left<right && nums[right]==nums[right-1]){
right--;
}
left++;
right--;
} else if (sum < target){ //如果sum<target,说明此时四数之和小了,需要left下标向右移动,使4数之和变大
left++;
} else { //如果sum>target,说明此时四数之和大了,因为数组是升序,需要right下标向左移动,使4数之和变小
right--;
}
}
}
}
//因为返回值是一个List<List<Integer>>, 所以这里需要将集合Set中的多个List, 添加到返回值List中
ArrayList<List<Integer>> result = new ArrayList<>();
result.addAll(hashSet);
return result;
}
}
输出:
待检查的数组为:
[1,0,-1,0,-2,2]
目标值为:0
原始数组中,满足条件的四元组为:
[[-2, 0, 0, 2],[-2, -1, 1, 2],[-1, 0, 0, 1]]Process finished with exit code 0
19. 删除链表的倒数第 N 个结点
题目:
给你一个链表,删除链表的倒数第
n
个结点,并且返回链表的头结点。
示例 2:
输入:head = [1], n = 1
输出:[]
示例 3:输入:head = [1,2], n = 1
输出:[1]
提示:
链表中结点的数目为 sz
1 <= sz <= 30
0 <= Node.val <= 100
1 <= n <= sz
代码:
package com.my.test;
public class ListNode {
int val; //数据 :节点值
ListNode next; //对象 :指向下一个节点对象。在Java中没有指针的概念,Java中的引用和C语言的指针类似
ListNode() {
}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
package com.my.test;
public class removeNthNodeFromEnd {
public static void main(String[] args) {
//准备链表
ListNode head = new ListNode(1);
ListNode node1 = new ListNode(2);
ListNode node2 = new ListNode(3);
ListNode node3 = new ListNode(4);
ListNode node4 = new ListNode(5);
head.next = node1;
node1.next = node2;
node2.next = node3;
node3.next = node4;
node4.next = null;
//输出原始链表
System.out.println("原始链表为:");
System.out.print("[");
int length = 5;
ListNode tmp = new ListNode(0, head);
for(int i=1; i<=length; i++){
if(i == length){
System.out.print(tmp.next.val);
tmp = tmp.next;
} else {
System.out.print(tmp.next.val+",");
tmp = tmp.next;
}
}
System.out.println("]");
int n = 2;
System.out.println("要删除的是:倒数第"+n+"个结点");
System.out.println("**********************************************************");
//调用方法,删除某个结点
ListNode result = removeNthNodeFromEnd(head, n);
//输出结果链表
System.out.println("删除倒数第"+n+"个结点后的链表为:");
System.out.print("[");
ListNode tmp2 = new ListNode(0, head);
for(int i=1; i<=length-1; i++){
if(i == length){
System.out.print(tmp2.next.val);
tmp2 = tmp2.next;
} else {
System.out.print(tmp2.next.val+",");
tmp2 = tmp2.next;
}
}
System.out.println("]");
System.out.println("返回的链表头结点的值为:"+result.val);
}
public static ListNode removeNthNodeFromEnd(ListNode head, int n){
ListNode dummyHead = new ListNode(); //定义虚拟头节点,指向实际的头节点
dummyHead.val = 0;
dummyHead.next = head;
//left和right初始都指向虚拟头节点
ListNode left = dummyHead; //left节点,会指向要删除的节点的前一个节点
ListNode right = dummyHead; //right节点,下面会操作移动节点指针,当right指向null时,它与left之间相差n个节点,n表示要删除的是链表倒数第n个节点
//先让快指针right向前移动n+1步
for(int i=0; i<=n; i++){
right = right.next;
}
//让指针left和right同时向前移动,每次移动一步,直到right指向null
while( right != null){
right = right.next;
left = left.next;
}
//此时,left所指向的下一个节点,就是要删除的节点
//删除操作:left所指节点的后继指针指向待删除节点的下一个节点,然后待删除节点delNode的后继指针指向null,即可将倒数第n个节点删除
ListNode delNode = left.next;
left.next = delNode.next;
delNode.next = null;
//返回头节点
return dummyHead.next;
}
}
输出:
原始链表为:
[1,2,3,4,5]
要删除的是:倒数第2个结点
**********************************************************
删除倒数第2个结点后的链表为:
[1,2,3,5,]
返回的链表头结点的值为:1Process finished with exit code 0
20. 有效的括号
题目:
给定一个只包括 '(',')','{','}','[',']' 的字符串 s ,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
示例 1:
输入:s = "()"
输出:true
示例 2:输入:s = "()[]{}"
输出:true
示例 3:输入:s = "(]"
输出:false
示例 4:输入:s = "([)]"
输出:false
示例 5:输入:s = "{[]}"
输出:true
提示:
1 <= s.length <= 104
s 仅由括号 '()[]{}' 组成
代码:
package com.my.test;
import java.util.Stack;
public class blacketsIsValid {
public static void main(String[] args) {
String str = "{[]()";
System.out.println("待检查的字符串为(只包括 '(',')','{','}','[',']'):" + str);
boolean result = blacketsIsValid(str);
if(result){
System.out.println("该字符串有效");
} else {
System.out.println("该字符串无效");
}
}
//利用栈来实现
public static boolean blacketsIsValid(String str){
Stack<Character> stack = new Stack<>();
int length = str.length();
for(int i=0; i<length; i++){
char c = str.charAt(i);
if(c == '(' || c == '[' || c == '{'){ //如果是左括号,则入栈
stack.push(c);
} else { //如果是右括号
if(stack.isEmpty()){ //如果此时栈内为空,则刚从字符串中取出的右括号没有相应的左括号匹配,返回false
return false;
}
char left = stack.pop(); //如果此时栈不空,则弹出栈顶字符,然后匹配栈顶字符和刚从字符串中取出的字符是否是一对有效括号
if((left=='(' && c!=')') || (left=='[' && c!=']') || (left=='{' && c!='}')){
return false; //如果不是有效的括号,则返回false
}
}
}
return stack.isEmpty(); //遍历完字符串之后,如果栈为空,表示字符串中都匹配到了有效的括号,返回true. 如果栈不空,则说明还有括号没找到匹配,返回false
}
}
输出:
待检查的字符串为(只包括 '(',')','{','}','[',']'):{[]()
该字符串无效!Process finished with exit code 0
21. 合并两个有序链表
题目:
将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例 2:
输入:l1 = [], l2 = []
输出:[]
示例 3:
输入:l1 = [], l2 = [0]
输出:[0]
提示:
两个链表的节点数目范围是 [0, 50]
-100 <= Node.val <= 100
l1 和 l2 均按 非递减顺序 排列
代码:
package com.my.test;
public class ListNode {
int val; //数据 :节点值
ListNode next; //对象 :指向下一个节点对象。在Java中没有指针的概念,Java中的引用和C语言的指针类似
ListNode() {
}
ListNode(int val) {
this.val = val;
}
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
package com.my.test;
public class mergeTwoLists {
public static void main(String[] args) {
//准备链表1
ListNode head1 = new ListNode(1);
ListNode node11 = new ListNode(2);
ListNode node12 = new ListNode(5);
head1.next = node11;
node11.next = node12;
node12.next = null;
//准备链表2
ListNode head2 = new ListNode(1);
ListNode node21 = new ListNode(3);
ListNode node22 = new ListNode(4);
head2.next = node21;
node21.next = node22;
node22.next = null;
//输出原始链表1
System.out.println("原始链表1为:");
System.out.print("[");
int length1 = 3;
ListNode tmp1 = new ListNode(0, head1);
for(int i=1; i<=length1; i++){
if(i == length1){
System.out.print(tmp1.next.val);
tmp1 = tmp1.next;
} else {
System.out.print(tmp1.next.val+",");
tmp1 = tmp1.next;
}
}
System.out.println("]");
//输出原始链表2
System.out.println("原始链表2为:");
System.out.print("[");
int length2 = 3;
ListNode tmp2 = new ListNode(0, head2);
for(int i=1; i<=length2; i++){
if(i == length2){
System.out.print(tmp2.next.val);
tmp2 = tmp2.next;
} else {
System.out.print(tmp2.next.val+",");
tmp2 = tmp2.next;
}
}
System.out.println("]");
System.out.println("***************************************************");
//调用方法,合并两个链表
ListNode result = mergeTwoLists(head1, head2);
//输出合并后的链表
System.out.println("合并后的链表为:");
System.out.print("[");
ListNode tmp3 = new ListNode(0, result);
int length = length1 + length2;
for(int i=1; i<=length; i++){
if(i == length){
System.out.print(tmp3.next.val);
tmp3 = tmp3.next;
} else {
System.out.print(tmp3.next.val+",");
tmp3 = tmp3.next;
}
}
System.out.println("]");
}
//递归的思想
public static 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;
}
}
}
输出:
原始链表1为:
[1,2,5]
原始链表2为:
[1,3,4]
***************************************************
合并后的链表为:
[1,1,2,3,4,5]Process finished with exit code 0
22. 括号生成
题目:
数字 n 代表生成括号的对数,请你设计一个函数,用于能够生成所有可能的并且 有效的 括号组合。
示例 1:
输入:n = 3
输出:["((()))","(()())","(())()","()(())","()()()"]
示例 2:输入:n = 1
输出:["()"]
提示:
1 <= n <= 8
代码:
参考此文,自己动手练了一遍,可以直接看原博:力扣刷题:括号生成(java实现)
/*
合法的字符串的特点:
(1)字符串长度是括号个数n的两倍
(2)左括号和右括号个数相等
(3)如果左括号和右括号个数相等,但是长度还没到2*n的时候,下一个必定是左括号
(4)如果左括号比右括号多,并且左括号个数小于n,下一个可以是左括号,也可以是右括号
(5)如果左括号比右括号多,并且左括号个数等于n,下一个必定是右括号
*/
package com.my.test;
import java.util.ArrayList;
import java.util.List;
//深度优先
public class generateParenthesis {
public static void main(String[] args) {
int n = 4;
System.out.println(n + "对括号的所有可能并且有效的组合为:");
List<String> result = generateParenthesis(n);
System.out.print('[');
for(int i=0; i<result.size(); i++){
if(i == result.size()-1){
System.out.print("\"" + result.get(i) + "\"");
} else {
System.out.print("\"" + result.get(i) + "\",");
}
}
System.out.print(']');
}
public static List<String> generateParenthesis(int n){
List<String> list = new ArrayList<>(); //list存放符合条件的多个字符串
if(n==0){
return list;
}
StringBuilder sb = new StringBuilder();
getRes(list, n, 0, 0, sb);
return list;
}
//n表示题目的括号数,left表示左括号个数,right表示右括号个数,
public static void getRes(List<String> list, int n, int left, int right, StringBuilder sb){
int len = sb.length(); //存放结果的字符串的长度
if(len == 2*n){ //如果存放结果的字符串长度是所给括号数的两倍,添加到集合中
list.add(sb.toString());
} else {
if(left == right){ //如果字符串中左括号数和右括号数一样,但是长度还没到2*n,下一个必定是左括号
sb.append('(');
getRes(list, n, left+1, right, sb);
sb.deleteCharAt(len); //删除调用函数前添加的‘(’,不然会对后面的代码造成影响
} else if(left > right && left < n){ //如果左括号比右括号多,并且左括号个数小于n,下一个可以是左括号,也可以是右括号
char[] array = new char[]{'(', ')'};
for(char c: array){
sb.append(c);
if(c == '('){
getRes(list, n, left+1, right, sb);
} else {
getRes(list, n, left, right+1, sb);
}
sb.deleteCharAt(len);
}
} else if(left > right && left == n){ //如果左括号比右括号多,并且左括号个数等于n,下一个必定是右括号
sb.append(')');
getRes(list, n, left, right+1, sb);
sb.deleteCharAt(len);
}
}
}
}
输出:
4对括号的所有可能并且有效的组合为:
["(((())))","((()()))","((())())","((()))()","(()(()))","(()()())","(()())()","(())(())","(())()()","()((()))","()(()())","()(())()","()()(())","()()()()"]
Process finished with exit code 0
23. 合并K个升序链表
24. 两两交换链表中的节点
更新中.......................