力扣(重点题)

文章目录

      • 力1. 两数之和
      • 力 2. 两数相加
      • 力 3. 无重复字符的最长子串
      • 力 5. 最长回文子串
      • 力7. 整数反转
      • 力9. 回文数
      • 力14. 最长公共前缀
      • 力15. 三数之和
      • 力16. 最接近的三数之和
      • 力 18四数之和
      • 力19. 删除链表的倒数第N个节点
      • 力20. 有效的括号
      • 力21. 合并两个有序链表
      • 力22. 括号生成
      • 力32 最长有效括号
      • 力扣25 . K个一组翻转链表

力1. 两数之和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]

class Solution {
     
    public int[] twoSum(int[] nums, int target) {
     
		for (int i = 0; i < nums.length; i++) {
     
            for (int j = i + 1; j < nums.length; j++) {
     
                if (target == nums[i] + nums[j]) {
     
                    return new int[]{
     i, j};
                }
            }
        }
        throw new IllegalArgumentException("没有两数之和");
    }
}

力 2. 两数相加

给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储
的,并且它们的每个节点只能存储 一位 数字。如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
class Solution {
     
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
     
        //创建头结点之前的结点
        ListNode head=new ListNode(0);
        ListNode pre=head;
        //设置辅助结点
        ListNode p1=l1, p2=l2;
        int sum=0;
        //循环条件:两个链表不为空,继续遍历
        while (p1!=null||p2!=null){
     
            if (p1!=null){
     
                sum+=p1.val;//值
                p1=p1.next;//移到下一个节点
            }
            if (p2!=null){
     
                sum+=p2.val;
                p2=p2.next;
            }
            //新链表的节点
            pre.next=new ListNode(sum%10);
            pre=pre.next;//新链表后移
            sum=sum/10;//每次进位是1还是0,重新放到下一次计算
        }
        //预防最后的节点进位为1
        if (sum==1){
     
            pre.next=new ListNode(1);
        }
        return head.next;
    }
}

力 3. 无重复字符的最长子串

给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
示例 1:
输入: "abcabcbb"
输出: 3 
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例 2:
输入: "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1class Solution {
     
    public int lengthOfLongestSubstring(String s) {
     
        // 哈希集合,记录每个字符是否出现过
        Set<Character> occ = new HashSet<Character>();
        int n = s.length();
        // 右指针,初始值为 -1,相当于我们在字符串的左边界的左侧,还没有开始移动
        int rk = -1, ans = 0;
        for (int i = 0; i < n; ++i) {
     
            if (i != 0) {
     
                // 左指针向右移动一格,移除一个字符
                occ.remove(s.charAt(i - 1));
            }
            while (rk + 1 < n && !occ.contains(s.charAt(rk + 1))) {
     
                // 不断地移动右指针
                occ.add(s.charAt(rk + 1));
                ++rk;
            }
            // 第 i 到 rk 个字符是一个极长的无重复字符子串
            ans = Math.max(ans, rk - i + 1);
        }
        return ans;
    }
}

力 5. 最长回文子串

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

示例 1:

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。

    public String longestPalindrome(String s) {
     
        if (s.isEmpty()) {
     
            return "";
        }
        int len = s.length();
        // 定义二维数组记录原字符串 i 到 j 区间是否为回文子串。
        boolean[][] dp = new boolean[len][len];
        // 记录遍历过的最长回文子串。
        String ans = "";
        // 记录遍历过的最长回文子串长度。
        int maxLen = 0;
        // 遍历元素并得到包含当前元素之前字符串的最大回文子串。
        for (int j = 0; j < s.length(); j++) {
     
            for (int i = 0; i <= j; i++) {
     
                // 状态转移,判断记录 i 到 j 位置是否为回文子串。
                dp[i][j] = s.charAt(i) == s.charAt(j)
                        && ((j - i <= 2) || dp[i + 1][j - 1]);
                if (dp[i][j]) {
     
                    // 判断更新记录遍历过的最长回文子串。
                    if (j - i + 1 > maxLen) {
     
                        maxLen = j - i + 1;
                        ans = s.substring(i, j + 1);
                    }
                }
            }
        }
        return ans;
    }
}

力7. 整数反转

 /**
     * 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
     * 示例 1:
     * 输入: 123
     * 输出: 321
     *  示例 2:
     * 输入: -123
     * 输出: -321
     * 示例 3:
     * 输入: 120
     * 输出: 21
     * */
    public int reverse(int x) {
     
        long res=0;
        while (x!=0){
     
            res=res*10+x%10;
            x/=10;
            if(res>Integer.MAX_VALUE||res<Integer.MIN_VALUE)return 0;
        }
        return (int) res;
    }

力9. 回文数

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
示例 1:
输入: 121
输出: true
示例 2:
输入: -121
输出: false
解释: 从左向右读,-121 。 从右向左读,121- 。因此它不是一个回文数。
//思路:就是正序和逆序值一样,那么可以考虑stringBuilder.reverse方法逆序输出,判断是否相等
public class Solution {
     
    public boolean isPalindrome(int x) {
     
        //定义一个函数判断正序和逆序是否相等。
        boolean b = HuiWen(String.valueOf(x));
        return b;
    }
    public boolean HuiWen(String s){
     
        StringBuilder stringBuilder=new StringBuilder(s);
        StringBuilder reverse = stringBuilder.reverse();
        //看从左往右读和从右往左读,是否一致
        if (s.equals(reverse.toString())){
     
            return true;
        }
        return false;
    }
}

力14. 最长公共前缀

/**
 *编写一个函数来查找字符串数组中的最长公共前缀。
 * 如果不存在公共前缀,返回空字符串 ""。
 * 示例 1:
 * 输入: ["flower","flow","flight"]
 * 输出: "fl"
 * 示例 2:
 * 输入: ["dog","racecar","car"]
 * 输出: ""
 * 解释: 输入不存在公共前缀。
 * */
public class Solution {
     
    public static void main(String[] args) {
     
        String[] strs={
     "dog","racecar","car"};
        longestCommonPrefix(strs);
    }
    public static String longestCommonPrefix(String[] strs) {
     
        //越界检查
        if (strs==null||strs.length==0) return "";
        //如果该字符串有数组,则另第一个下标值为基准值,与其他值逐一比较
        String res = strs[0];
        for (int i = 1; i <strs.length; i++) {
     
            //indexOf:父字符串首次出现子字符串的第一个字母下标值(在父字符串检查下标出现位置)
            //因为字符串数组公共前缀,所以只能是数组全部字符串的首位相同才符合公共前缀
            while (strs[i].indexOf(res)!=0){
     
                //每次截取到res字符串的倒数第二位,左闭右开
                res=res.substring(0,res.length()-1);
            }
        }
        return res;
    }
}

力15. 三数之和

/**
 * 给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元
 * 素 a,b,c ,使得 a + b + c = 0 ?请你找出所有满足条件且不重复的三元组。
 * 注意:答案中不可以包含重复的三元组。
 * 示例:
 * 给定数组 nums = [-1, 0, 1, 2, -1, -4],
 * 满足要求的三元组集合为:
 * [
 *   [-1, 0, 1],
 *   [-1, -1, 2]
 * ]
 * */
//双指针求和问题
public class Solution {
     
    public List<List<Integer>> threeSum(int[] nums) {
     
        if(nums.length==0||nums==null) return new ArrayList<>();
        //先对数组进行升序排列
        Arrays.sort(nums);
        //无序不可重复数组
        Set<List<Integer>> set =new HashSet<>();

        //每循环一个nums[i],都需要它的下一个数nums[left]和最右边的nums[right]求和判断=0
        for (int i = 0; i < nums.length; i++) {
     
            //左右指针:判断nums[i]+nums[left]+nums[right]=0
            int left=i+1,right=nums.length-1;
            //左右指针都相等还没结果,就退出循环
            while (left<right){
     
                if (nums[i]+nums[left]+nums[right]==0){
     
                    //加入的是不可重复的三元组。
                    set.add(Arrays.asList(nums[i],nums[left],nums[right]));
                    //满足条件后,在继续找下一个满足条件的
                    left++;
                    right--;
                }else if (nums[i]+nums[left]+nums[right]<0){
     
                    //按照升序排列后,nums[right]总是最大的,加上最大都<0,只能是left往右移,使数更大
                    left++;
                }else if (nums[i]+nums[left]+nums[right]>0){
     
                    //既然已经大于0,只能right往左移,使得数更小
                    right--;
                }
            }
        }
        //将Set集合加入List集合,返回List类型
        List<List<Integer>> list=new ArrayList<>();
        //addAll(Collection集合)
        list.addAll(set);
        return list;
    }
}

力16. 最接近的三数之和

import java.util.Arrays;
/**
 * 给定一个包括 n 个整数的数组 nums 和 一个目标值 target。
 * 找出 nums 中的三个整数,使得它们的和与 target 最接近。返回这三个数的和。
 * 假定每组输入只存在唯一答案。
 * 示例:
 * 输入:nums = [-1,2,1,-4], target = 1
 * 输出:2
 * 解释:与 target 最接近的和是 2 (-1 + 2 + 1 = 2) 。
 * 提示:
 * 3 <= nums.length <= 10^3
 * -10^3 <= nums[i] <= 10^3
 * -10^4 <= target <= 10^4
 * */
public class Solution {
     
    public int threeSumClosest(int[] nums, int target) {
     
        //不需要下标值,所以任意顺序都行,做个升序排列
        Arrays.sort(nums);
        //初始化返回值res
        int res=nums[0]+nums[1]+nums[2];
        for (int i = 0; i < nums.length; i++) {
     
            int left=i+1;//左指针:当前循环值的下一位
            int right=nums.length-1;//右指针:数组的最后一位:最大的值(升序排列)
            while (left<right){
     
                //每次判断当前的三位数和上一轮的三位数和res谁更接近target
                if (Math.abs(nums[i]+nums[left]+nums[right]-target)< Math.abs(res-target)){
     
                    res=nums[i]+nums[left]+nums[right];
                }else if (nums[i]+nums[left]+nums[right]>target){
     
                    //升序数组:和大于target,right--,保证右指针左移,使数变小
                    right--;
                }else if (nums[i]+nums[left]+nums[right]<target){
     
                    //和小于,只能左指针往右移
                    left++;
                }else {
     
                    return res;
                }
            }
        }
        return res;
    }
}

力 18四数之和

给定一个包含 n 个整数的数组 nums 和一个目标值 target,判断 nums 中是否存在四个元素 a,b,c 和 d ,使得 a + b + c + d 的值与 target 相等?找出所有满足条件且不重复的四元组。
注意:
答案中不可以包含重复的四元组。
示例:
给定数组 nums = [1, 0, -1, 0, -2, 2],和 target = 0。
满足要求的四元组集合为:
[
  [-1,  0, 0, 1],
  [-2, -1, 1, 2],
  [-2,  0, 0, 2]
]
/**
 *与三数之和一样的思路
 * */
public class Solution {
     
    public List<List<Integer>> fourSum(int[] nums, int target){
     
        if(nums==null||nums.length<4) return new ArrayList<>();
        //排序
        Arrays.sort(nums);
        HashSet<List<Integer>> set = new HashSet<>();
        int length=nums.length;
        //i,j,left,right :固定i,j循环,然后双指针left、right向中间靠
        for (int i = 0; i < length; i++) {
     
            for (int j = i+1; j < length; j++) {
     
                int left=j+1;//左指针
                int right=nums.length-1;//右指针
                while (left<right){
     
                    if (nums[i]+nums[j]+nums[left]+nums[right]==target){
     
                        set.add(Arrays.asList(nums[i],nums[j],nums[left],nums[right]));
                        left++;
                        right--;
                    }else if (nums[i]+nums[j]+nums[left]+nums[right]>target){
     
                        right--;
                    }else {
     
                        left++;
                    }
                }
            }
        }
        List<List<Integer>> list=new ArrayList<>();
         list.addAll(set);
         return list;
    }
}

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

给定一个链表,删除链表的倒数第 n 个节点,并且返回链表的头结点。
示例:
给定一个链表: 1->2->3->4->5, 和 n = 2.
当删除了倒数第二个节点后,链表变为 1->2->3->5.
class Solution {
     
    public ListNode removeNthFromEnd(ListNode head, int n) {
     
        ListNode start =new ListNode(0);
        ListNode slow=start;
        ListNode fast=start;
        start.next=head;
        for (int i = 0; i < n; i++) {
     
            fast=fast.next;
        }
        while (fast.next!=null){
     
            fast=fast.next;
            slow=slow.next;
        }
        slow.next=slow.next.next;
        return start.next;
    }
}

力20. 有效的括号

给定一个只包括 '('')''{''}''['']' 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: "()"
输出: true
class Solution {
     
    public boolean isValid(String s) {
     
        if(s==null||s.length()==0) return true;
        Stack<Character> stack = new Stack<>();
        for (int i = 0; i < s.length(); i++) {
     
            //出现三个左括号的情况:右括号入栈
            if (s.charAt(i)=='('){
     
                stack.push(')');
            }else if (s.charAt(i)=='{'){
     
                stack.push('}');
            }else if (s.charAt(i)=='['){
     
                stack.push(']');
            }else {
     //出现右括号的情况:判断栈里的是否和当前括号相等
                //stack.isEmpty()是只有一个括号的情况:如 )
                //出栈的和当前的相等,说明之前有左括号的情况才入栈,现在又相等,就是符合
                if (stack.isEmpty()||stack.pop()!=s.charAt(i))return false;
            }
        }
        //栈为空:说明之前出栈就相等了
        return stack.isEmpty();
    }
}

力21. 合并两个有序链表

将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
public class Solution {
     
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
     
        //定义一个头结点之前的空节点暂存
        ListNode dump=new ListNode(0);
        //定义一个cur指针
        ListNode cur=dump;
        //两个链表的节点都不为空时
        while (l1!=null&&l2!=null){
     
            //l1的值小于l2,就将cur的下一个节点指向较小的节点l1,之后l1后移
            if (l1.val<l2.val){
     
                cur.next=new ListNode(l1.val);
                l1=l1.next;
            }else {
     //cur指向l2,之后l2后移
                cur.next=new ListNode(l2.val);
                l2=l2.next;
            }
            //cur指针后移
            cur=cur.next;
        }
        //当不满足上述条件时
        if (l1!=null){
     //l1不为空,则l2就为空,
            //只有l1不为空,而且l1为升序,剩下的节点 也是升序排列,直接将cur.next指向剩下的l1
            cur.next=l1;
        }else {
     
            //l2不为空或者l1和l2都是空。
            //l2不为空:剩下节点升序,直接cur.next指向剩下的l2
            //都为空,说明节点已经按照题目排序完,即使cur.next=l2;也是cur.next指向null
            cur.next=l2;
        }
        return dump.next;
    }
}

力22. 括号生成

public class Solution {
     
    public List<String> generateParenthesis(int n) {
     
        List<String> res =new ArrayList<>();
        //执行深度优先(回朔算法:backtracking)
        dfs("",n,n,res);
        return res;
    }
    /**减法操作: left-1,right-1
     * @param curString 表示当前递归的结果
     * @param left 表示左括号还剩余的数量
     * @param right 表示右括号还剩余的数量
     * @param res 返回的结果集
     * */
    public void dfs(String curString,int left,int right,List<String>res){
     
        //回溯终止条件
        if (left==0&&right==0){
     
            res.add(curString);
            return;
        }
        //减枝条件:左边括号剩余的数量>右边括号剩余的数量,配不了了
        if (left>right) {
     
            return;
        }
        //一直增加左括号,直到左边括号剩余数量为0
        if (left>0){
     
            dfs(curString+"(",left-1,right,res);
        }
        //一直增加右括号,直到右边括号剩余数量为0
        if (right>0){
     
            dfs(curString+")",left,right-1,res);
        }
    }
}

力32 最长有效括号

给定一个只包含 '('')' 的字符串,找出最长的包含有效括号的子串的长度。
示例 1:
输入: "(()"
输出: 2
解释: 最长有效括号子串为 "()"
示例 2:
输入: ")()())"
输出: 4
解释: 最长有效括号子串为 "()()"
public int longestValidParentheses(String s) {
     
        //首先判断s
        if(s==null||s.length()==0) return 0;
        //定义有效括号的起始位置start,返回字符串长度max
        int start=0,max=0;
        Stack<Integer> stack = new Stack<>();
        //定义index
        for (int index = 0; index < s.length(); index++) {
     
            //判断是否左括号,左括号的下标就入栈;else是右括号分支
            if (s.charAt(index)=='('){
     
                stack.push(index);
            }else {
     
                //首先判断栈里是否存在'(',不存在'(',说明有效配对不了,只能把有效括号起始位置后移一位
                if (stack.empty()){
     
                    start=index+1;
                }else {
     
                    //栈不为空,说明存在'(',这时直接出栈,和右括号匹配
                    stack.pop();
                    //出栈后在判断有效的字符长度max
                    if (stack.empty()){
     
                        max=Math.max(max,index-start+1);
                    }else {
     
                        max=Math.max(max,index-stack.peek());
                    }
                }
            }
        }
        return max;
    }

力扣25 . K个一组翻转链表

给你一个链表,每 k 个节点一组进行翻转,请你返回翻转后的链表。
k 是一个正整数,它的值小于或等于链表的长度。
如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
示例:
给你这个链表:1->2->3->4->5
当 k = 2 时,应当返回: 2->1->4->3->5
当 k = 3 时,应当返回: 3->2->1->4->5
class Solution {
     
    public ListNode reverseKGroup(ListNode head, int k) {
     
        ListNode next = head;
        int i = 0;
        //找到下一组k个节点现在的头节点
        for(i = 0; i < k; i++){
     
            if(next == null)
                break;
            next = next.next;
        }
        //节点数不足k个直接返回head
        if(i < k)
            return head;
        ListNode cur = head.next;
        ListNode pre = head;
        ListNode temp;
        //递归,将head.next指向下一组k个节点反转后的头节点
        head.next = reverseKGroup(next, k);
        while(cur != next){
     
            temp = cur.next;
            cur.next = pre;
            pre = cur;
            cur = temp;
        }
        //返回反转后的头节点
        return pre;
    }
}

你可能感兴趣的:(#,算法)