LeetCode代码刷题(17~24)

目录

17. 电话号码的字母组合

18. 四数之和

19. 删除链表的倒数第 N 个结点

20. 有效的括号

21. 合并两个有序链表

22. 括号生成

23. 合并K个升序链表

24. 两两交换链表中的节点


【写在前面】

前文参考: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,]
返回的链表头结点的值为:1

Process 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. 两两交换链表中的节点

更新中.......................

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值