leetcode前200+剑指offer重置版

博客分享了LeetCode多道题的解题思路,如寻找两个有序数组中位数需二分法,利用求第K小的数更新K、减少搜索空间;三数之和用sort + 双指针且不用set去重;删除链表倒数第N个节点要利用好dummy节点等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

leetcode1 两数之和

class Solution {
    public int[] twoSum(int[] nums, int target) {
        //map里面存储着遍历过的值和索引
        HashMap<Integer,Integer>map = new HashMap<>();
        for(int i =0;i<nums.length;i++){
            //查看map中是否有和当前值配对的值,如果有返回结果如果没有,当前值扔进map
            if(map.containsKey(target-nums[i])){
                //返回并且创建int数组的方法
                return new int[]{i,map.get(target-nums[i])};
            }else{
                map.put(nums[i],i);
            }
        }
        return new int[2];
    }
}

leetcode2 两数相加

class Solution {
    //分析:逆序链表,非0开头,返回也是逆序。
    //必须新建一个链表存结果,然后留意进位即可。
    public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        ListNode dummy = new ListNode(0);
        int add = 0;
        ListNode cur = dummy;
        //如果其中一个不为空,那就继续循环
        while(l1!=null||l2!=null){
            //如果是空就按0处理,求和不影响
            int val1 = l1==null?0:l1.val;
            int val2 = l2==null?0:l2.val;
            int value = (val1+val2+add)%10;
            //进位
            add = (val1+val2+add)/10;
            ListNode temp = new ListNode(value);
            cur.next =temp;
            cur=cur.next;
            //如果是空了,不能后移,因为没有next指针
            if(l1!=null) l1=l1.next;
            if(l2!=null) l2=l2.next;
        }
        //循环出来之后,还有可能有一位进位
        if(add!=0){
            ListNode temp = new ListNode(add);
            cur.next = temp;
        }
        return dummy.next;
    }
}

leetcode3 无重复字符的最长子串

class Solution {
    public int lengthOfLongestSubstring(String s) {
        //分析:两个指针移动找到不重复的区间。
        //用一个数组记录是否出现过,如果没有出现过,右指针正产后移,
        //如果出现过,左指针右移把之前出现的位置移动到区间外,右指针正常后移
        boolean charFlag[]= new boolean[128];
        int left = 0,right = 1,res=0;
        //这个逻辑对长度为0和1的都得特殊处理
        if(s.length()==0)return 0;
        //左指针一开始就在0,表示0位置的字符已经算进去了
        charFlag[s.charAt(0)]=true;
        //如果长度为1,right直接就退出去了
        if(s.length()==1)return 1;
        while(right<s.length()){
            //如果可以右移,右移同时补充标记+更新res
            if(charFlag[s.charAt(right)]==false){
                charFlag[s.charAt(right)]=true;
                res = Math.max(res,right-left+1);
                right++;
            //如果不能右移了。已经有重复了,左指针移动,
            //把重复字符越过去,移动过程要更新标记数组
            }else{
                while(s.charAt(left)!=s.charAt(right)){
                    charFlag[s.charAt(left)]=false;
                    left++;
                }
                charFlag[s.charAt(left)]=false;
                left++;
            }
        }
        return res;
    }
}

leetcode4 寻找两个有序数组的中位数

log(m+n)的时间复杂度。
分析:
一定要二分,每次要减少一半的元素。
所以只能比较两个元素的中位数,然后依据三种情况排除。
整体思路利用求第K小的数来思考。不断更新K,减少搜索空间。
尤其要关注边界条件。

leetcode5 最长回文子串

class Solution {
    //分析:首先想到区间DP的思路
    //先对区间长度遍历,然后对起点遍历,j=i+l。
    //在循环过程中初始化dp数组。dp[i][j]表示i到j是否回文串。
    //dp[I][J]=true 状态转移方程见下代码
    public String longestPalindrome(String s) {
        int size = s.length();
        boolean [][] dp = new boolean[size][size];
        String res="";
        //区间dp固定两个循环
        for(int l = 0;l<size;l++){
            for(int i =0;i<size-l;i++){
                int j =i+l;
                //关于dp初始化l=0和l=1两种初始情况的初始化
                //分别是奇数长度的初始状态和偶数长度的初始状态
                if(l==0){
                    dp[i][j]=true;
                }
                else if(l==1){
                    if(s.charAt(i)==s.charAt(j)){
                        dp[i][j]=true;
                    }
                }
                //正常的DP状态转移方程,两端字符相等且中间一段已经是回文串
                else{
                    if(dp[i+1][j-1]==true&&s.charAt(i)==s.charAt(j)){
                        dp[i][j]=true;
                    }
                }
                //更新结果,通过res的长度判断是否需要更新
                if(dp[i][j]==true&&l+1>res.length()){
                    res=s.substring(i,j+1);
                }
            }
        }
        return res;
    }
}

leetcode6 Z 字形变换

class Solution {
    public String convert(String s, int numRows) {
        //分析:需要n个StringBuilder保存中间内容
        //需要完成index的更新
        StringBuilder [] array = new StringBuilder[numRows];
        //numRows==1需要特殊处理,在更新flag时有问题
        if(numRows==1)return s;
        //初始化数组
        for(int i =0;i<numRows;i++){
           array[i]=new StringBuilder();
        }
        //因为先更新index,后使用index,所以初始值为-1.保证第一个填入0的位置。
        int index = -1;
        boolean flag =true;
    
        for(int i=0;i<s.length();i++){
            //更新flag表示index增加还是减少
            if(flag==true&&index==numRows-1){
                flag=false; 
            }
            if(flag==false&&index == 0){
                flag=true;
            }
            //根据flag更新index
            if(flag ==true){
                index++;
            }else{
                index--;
            }
            //更新好index后把字符放入应该在的位置
            array[index].append(s.charAt(i));
        }
        //构造结果
        StringBuilder res = new StringBuilder();
        for(int i =0;i<numRows;i++){
            res.append(array[i]);
        }
        return res.toString();
    }
}

leetcode7 整数反转

class Solution {
    //分析:反转很简单,问题在于溢出
    public int reverse(int x) {
        //reverse保存要返回的结果
        int reverse =0;
        //想把整数转到负数统一处理,因为负数的范围大一些,最后再还原0
        boolean flagChange = false;
        if(x>0){
            x=-x;
            flagChange=true;
        }
        //开始反转
        while(x<0){
            int num = x%10;
            x=x/10;
            //预判一下要溢出了,返回0,一种是乘10就溢出,一种是乘10不溢出,
            //但是加num就溢出了。
            if(reverse<Integer.MIN_VALUE/10)return 0;
            if(reverse==Integer.MIN_VALUE/10&&num<Integer.MIN_VALUE%10){
                return 0;
            }
            reverse=reverse*10+num;
        }
        //还原符号
        if(flagChange==true){
            //还原的时候也有一个溢出的点,其实在上面也能处理掉,单独拉出来不容易遗忘
            if(reverse==Integer.MIN_VALUE)return 0;
            reverse=-reverse;
        }
        return reverse;
    }
}

数月之后发现新的官方题解,简直是优雅到极致了

class Solution {
    public int reverse(int x) {
        int reverseNum = 0;
        while(x!=0){
            //此处有证明,不需要额外判断,因为最后一位小于7就可以,因为x本身也在32位范围内,所以最后一位其实是小于2的
            if(reverseNum<Integer.MIN_VALUE/10||reverseNum>Integer.MAX_VALUE/10){
                return 0;
            }
            int num = x%10;
            x=x/10;
            reverseNum =reverseNum*10+num; 
        }
        return reverseNum;
    }
}

leetcode8 字符串转换整数

leetcode9 回文数

class Solution {
    //分析:还是按照整数反转的策略写,
    //回文都是两种情况,奇数长度和偶数长度需要注意。
    public boolean isPalindrome(int x) {
        //特殊情况:x小于0,x以0结尾(且不是0)一定不是回文且走下面的逻辑可能出问题
        if(x<0)return false;
        if(x%10==0&&x!=0)return false;
        int reverse = 0;
        //反转过程
        while(x>reverse){
            int num = x%10;
            x=x/10;
            reverse=reverse*10+num;
        }
        //两种情况,偶数和奇数(如果以0结尾,会在这块判断出问题)
        if(x==reverse||x==reverse/10)return true;
        return false;
    }
}

时隔数月再看这个题想到的解法
再reverse过程中比较就可以了。
x如果等于reverse或者x/10=reverse就可以
但是特殊情况多了一个,就是个位数的时候。

class Solution {
    public boolean isPalindrome(int x) {
        // 这几个特殊情况确实容易遗漏
        if(x<0)return false;
        if(x<10)return true;
        if(x%10==0)return false;
        int reverse = 0;
        while(x>reverse){
            int digit = x%10;
            x=x/10;
            reverse = reverse*10+digit;
            if(x==reverse||x/10==reverse)return true;
        }
        return false;
    }
}

leetcode 10 正则表达式匹配

leetcode 11 盛水最多的容器

class Solution {
    public int maxArea(int[] height) {
        int maxArea = 0;
        int left =0,right =height.length-1;
        while(left<right){
            maxArea = Math.max(maxArea, (right-left)*Math.min(height[left],height[right]));
            if(height[left]>=height[right]){
                right--;
            }else{
                left++;
            }
        }
        return maxArea;
    }
}

leetcode 12 整数转罗马数字

class Solution {
    public String intToRoman(int num) {
        String[] keyTable = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
        int [] valueTable = {1000,900,500,400,100,90,50,40,10,9,5,4,1};
        StringBuilder res = new StringBuilder();
        for(int i = 0;i<valueTable.length;i++){
            if(num>=valueTable[i]){
                num-=valueTable[i];
                res.append(keyTable[i]);
                i--;
            }
        }
        return res.toString();
    }
}

leetcode 13 罗马数转整数

class Solution {
    public int romanToInt(String s) {
        char[] keyTable = {'M','D','C','L','X','V','I'};
        int [] valueTable = {1000,500,100,50,10,5,1};
        HashMap<Character,Integer> vMap = new HashMap<>();
        for(int i=0;i<keyTable.length;i++){
            vMap.put(keyTable[i],valueTable[i]);
        }
        int ans = 0;
        for(int i=0;i<s.length();i++){
            if(i==s.length()-1){
                ans += vMap.get(s.charAt(i));
            }else if(vMap.get(s.charAt(i))>=vMap.get(s.charAt(i+1))){
              ans += vMap.get(s.charAt(i));
            }else{
              ans -= vMap.get(s.charAt(i));
            }
        }
        return ans;
    }
}

leetcode14 最长公共前缀

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if(strs.length == 0)return "";
        for(int i = 0;i<strs[0].length();i++){
            for(int j = 1 ;j<strs.length;j++){
                if(strs[j].length()<=i||strs[j].charAt(i)!=strs[0].charAt(i)){
                    return strs[0].substring(0,i);
                }
            }
        }
        return strs[0];
    }
}

leetcode 15 三数之和

sort + 双指针
核心在不用set去重

外层保证i不会相同。
指定left的时候要i更新之后赋值。 保证i不会和left赋值重复。
每次更新res后,右移左指针要跳过所有相同的数字。

这样i不会相同,left不会相同,自然不会有相同结果。

class Solution {
   public List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> res = new LinkedList<>();
        Arrays.sort(nums);
        for(int i = 0 ;i<nums.length;i++){
            int right = nums.length-1;
            while(i!=0 && i<nums.length&& nums[i]==nums[i-1]) i++;
            if(i==nums.length)return res;
            int left = i+1;
            while(left<right){
                if(nums[i]+nums[left]+nums[right]==0){
                    List<Integer> temp = new LinkedList<>();
                    temp.add(nums[i]);
                    temp.add(nums[left]);
                    temp.add(nums[right]);
                    res.add(temp);
                    left++;
                    while(left<right&&nums[left]==nums[left-1])left++;
                }else if((nums[i]+nums[left]+nums[right]<0)){
                    left++;
                }else{
                    right--;
                }
            }
        }
        return res;
    }
}

leetcode16 最接近的三数之和

class Solution {
    public int threeSumClosest(int[] nums, int target) {
        int res = nums[0]+nums[1]+nums[2];
        Arrays.sort(nums);
        for(int i = 0 ;i<nums.length;i++){
            int right = nums.length-1;
            int left = i+1;
            while(left<right){
                int sum = nums[i]+nums[left]+nums[right];
                if(sum==target){
                   return target;
                }else if(sum<target){
                    if(Math.abs(target - sum)<Math.abs(target-res)){
                        res = sum;
                    }
                    left++;
                }else{
                    if(Math.abs(target - sum)<Math.abs(target-res)){
                        res = sum;
                    }
                    right--;
                }
            }
        }
        return res;
    }
}```

## leetcode 17 电话号码字母组合
复习一下,DFS的恢复现场。
用String builder可以灵活增减char
```java
class Solution {
   List<String> res = new LinkedList<>();

    public List<String> letterCombinations(String digits) {
        String[] table = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
        if(digits.length()==0)return res;
        search(table,0, new StringBuilder(), digits);

        return res;
    }
    public void search(String[] table, int index, StringBuilder temp, String digits){
        if(index == digits.length()){
            res.add(temp.toString());
            return ;
        }
        for(int i = 0;i< table[digits.charAt(index)-'0'].length();i++){
            char ch = table[digits.charAt(index)-'0'].charAt(i);
            temp.append(ch);
            search(table,index+1, temp, digits);
            temp.deleteCharAt(temp.length()-1);
        }
    }
}

leetcode 18 四数之和

注意剪枝

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

这个题应该想到对head节点操作会有麻烦,所以dummy要用好。

public ListNode removeNthFromEnd(ListNode head, int n) {
        ListNode dummy = new ListNode(0);
        dummy.next = head;
        ListNode fast = dummy;
        ListNode slow = dummy;
        while(n!=0){
            fast = fast.next;
            n--;
        }
        while(fast.next!=null){
            fast = fast.next;
            slow = slow.next;
        }
        slow.next = slow.next.next;
        return dummy.next;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值