测开力扣之常考编程中等题--手撕

本文总结了LeetCode中等难度的编程题目,包括字符串处理、链表操作、数组问题、二叉树遍历等,强调了刷题的重点在于理解思路并亲手实践,以加深记忆。文中涉及的算法包括滑动窗口、DFS、BFS、动态规划等,旨在帮助读者提升编程能力。
摘要由CSDN通过智能技术生成

前三页 除了加星 其他都做了 第四页未看

没时间了,就不要把时间放在强迫症上,有重点的做题和复习,毕竟时间有限

注意:
不能草率省事,思路一定要自己写,准确的复述一遍,记得更深刻

刷透了,一定要刷够中等题不要抱着侥幸的想法
中等题一定要刷熟练,手撕腾讯三面(全排列)和快手一面(图像的dfs,岛屿的数量)都出了dfs

3 无重复的最长子串
剑指offer 48 最长不含重复字符的最长子字符串(同一道题)
题意:找出字符串中最长的不重复子串

class Solution {
   
    public int lengthOfLongestSubstring(String s) {
   
        int n=s.length();
        int k=-1;
        int max=0;
        Set<Character> res=new HashSet<>();
        for(int i=0;i<n;i++){
   
            if(i>0){
   
                res.remove(s.charAt(i-1));
            }
            while(k+1<n && res.add(s.charAt(k+1))){
   
                k++;
                res.add(s.charAt(k));
            }
            max=Math.max(k-i+1,max);
        }
        return max;
    }
}

1 思路:
滑动窗口:双指针问题,左指针起始为i,右指针为-1
1)重复,用Set来盛放字符;遍历字符串,从0开始
2)每遍历一个起始点,就查找从起始点开始的最大元素的索引,更新最大值
3)当从新的起点开始的时候,移除他的上一个元素,滑动串口的右边界K++(开始为-1),左边界开始为i
2 )API:
set.remove(ele)
set.contains(ele)
set.add(ele);

142 环形链表
题意:找出入环的节点

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
   
    public ListNode detectCycle(ListNode head) {
   
        Set<ListNode> res=new HashSet<>();
        ListNode temp=head;
        while(temp!=null){
   
            if(res.contains(temp)){
   
                return temp;
            }
            res.add(temp);
            temp=temp.next;
        }
    return null;   
    }
}

1 思路:
1.1)用set遍历链表将节点依次加入
1.2)如加入过程中出现了已经包含的节点,那么返回当前遍历的节点
2 数据结构
Set: set.contains(ele)

15 三数之和
题意:给一个数组,计算三个数的和为0,找出所有的组合,并添加进list中。不能添加进去重复的List

class Solution {
   
    public List<List<Integer>> threeSum(int[] nums) {
   
        List<List<Integer>> res=new LinkedList<>();
        if(nums==null || nums.length<=2){
   return res;}
        Arrays.sort(nums);
        for(int i=0;i<nums.length-2;i++){
   
            if(nums[i]>0){
   break;}//结束
            if(i>0 && nums[i]==nums[i-1]) continue;
            int left=i+1,right=nums.length-1;
            //必须有一个循环,防止越界
            while(left<right){
   
                List<Integer> temp=new LinkedList<>();
                 int sum=nums[i]+nums[left]+nums[right];
                if(sum==0){
   
                    //将数组变成 list
                    //res.add(new ArrayList<>(Arrays.asList(nums[i],nums[left],nums[right])));
                    temp.add(nums[i]);
                    temp.add(nums[left]);
                    temp.add(nums[right]);
                    res.add(temp); //别忘记了
                    left++;
                    right--;
                    //left<right 防止越界, 和之前出现过的元素比较
                    while(left<right && nums[left]==nums[left-1]){
   left++;}
                    while(left<right && nums[right]==nums[right+1]){
   right--;}
                }else if(sum>0){
   
                    right--;
                }else{
   
                    left++;
                }
            }
        }
        return res;
    }
}

1 思路:三指针问题
1)将数组进行一个排序,i从0开始遍历数组
2)定义左右指针,左指针是L=i+1,右指针从R=nums.length-1开始;
2.1)遍历的时候,先看num[i]>0,若是,则结束循环,返回函数值
2.1)看(i>0 && num[i]==num[i-1])若是相等,那么开始下一次循环
3)求出三数之和,如果和为0,那么将三个数添加进List中,
3.1)看是否有重复的List,若是nums[L]=nums[L+1],那么L++;循环条件L<R;
3.2)nums[R]=nums[R-1],那么R–;循环条件L<R;
3.3)循环结束后依然要 R–和L++
4)若是 三数之和小于 0,那么L++;大于0,那么R–;
2数据结构
数组 和 list
API:List<List> res=new ArrayList<List>();
list.add();

468验证IP地址
题意:给一个字符串,看是否是正确的IP地址

//注意: 以“.”分割,得加上转义符 \\. 注意|| 和 && d的用法
//判断是否是十六进制或者数字的时候 将包括的情况写进去在写反。要不情况太多,不要好写
//!((ch>='0' && ch<='9')||(ch>='a'&&ch<='f') ||(ch>='A' && ch<='F'))
class Solution {
   
    public String validIPAddress(String IP) {
   
        if(IP.contains(".")){
   
            if(IP.endsWith(".") || IP.startsWith(".")){
   
                return "Neither";
            }
            //注意转义符号
            String[] str=IP.split("\\.");
            if(str.length!=4){
   
                return "Neither";
            }
            for(String ele:str){
   
                if(ele.length()<1 || ele.length()>3){
   
                    return "Neither";
                }
                if(ele.startsWith("0") && ele.length()!=1){
   
                    return "Neither";
                }
                //判断是否是一定范围的数字
                if(!isNum(ele)){
   
                    return "Neither";
                }
            }
            return "IPv4";
        }else if(IP.contains(":")){
   
            if(IP.endsWith(":") || IP.startsWith(":")){
   
                return "Neither";
            }
            String[] str1=IP.split(":");
            if(str1.length!=8){
   
                return "Neither";
            }
            for(String ele:str1){
   
                if(ele.length()<1 || ele.length()>4){
   
                    return "Neither";
                }
                if(!isHex(ele)){
   
                    return "Neither";
                }
            }
            return "IPv6";
        }
        return "Neither";
    }
    
    //判断是否是数字
    public boolean isNum(String str){
   
        int n=str.length();
        int sum=0;
        for(int i=0;i<n;i++){
   
            char ch=str.charAt(i);
            if(ch>'9' || ch<'0'){
   
             return false;
            }
            sum=sum*10+ch-'0';
        }
        return sum>=0 && sum<=255;
    }
    //判断是否是16进制
    public boolean isHex(String str){
   
        int n=str.length();
        for(int i=0;i<n;i++){
   
            char ch=str.charAt(i);
            //注意中间是&& 情况比较多,情况之外的选择
            if(!((ch>='0' && ch<='9')||(ch>='a'&&ch<='f') ||(ch>='A' && ch<='F'))){
   
               return false; 
            }
        }
        return true;
    }
}

IPv4 地址由十进制数和点来表示,每个地址包含 4 个十进制数,其范围为 0 - 255, 用(".")分割。比如,172.16.254.1;
同时,IPv4 地址内的数不会以 0 开头。比如,地址 172.16.254.01 是不合法的。
IPv6 地址由 8 组 16 进制的数字来表示,每组表示 16 比特。这些组数字通过 (":")分割。比如, 2001:0db8:85a3:0000:0000:8a2e:0370:7334 是一个有效的地址。而且,我们可以加入一些以 0 开头的数字,字母可以使用大写,也可以是小写。所以, 2001:db8:85a3:0:0:8A2E:0370:7334 也是一个有效的 IPv6 address地址 (即,忽略 0 开头,忽略大小写)。
然而,我们不能因为某个组的值为 0,而使用一个空的组,以至于出现 (:😃 的情况。 比如, 2001:0db8:85a3::8A2E:0370:7334 是无效的 IPv6 地址。
同时,在 IPv6 地址中,多余的 0 也是不被允许的。比如, 02001:0db8:85a3:0000:0000:8a2e:0370:7334 是无效的。

题目本身不难,考虑所有边界条件即可:
IPv4:
段地址数只能为4;
以0开头时只允许长度为1;
段地址必须是可以进行int()的字符串;
int()之后必须在[0,255]区间;
IPv6:
段地址数只能为8;
段地址只允许长度为[1,4]区间;
段地址每个字符必须是合法的16进制字符,例如G不合法;

1 思路:(将不是IPV的字母给拿出来,其他)
1)如果字符串中包括(.)为IPV4
1.1)如果以.结尾,那么不是
1.2)转成字符数组,如果数组的个数 不等于4 那么不是
1.3)遍历字符串中的每一个字符
1.31)字符的长度不是在1和3之间(0-255)
1.32)如果以0开头,长度不是1 那么不是
1.33)判断字符是否是数字,0-255区间(另写函数)
2)如果字符串中包括(:)为IPV6
2.1)如果以.结尾,那么不是
2.2)转成字符数组,如果数组的个数 不等于8 那么不是
2.3)遍历字符串中的每一个字符
1.31)字符的长度不是在1和4之间(0-255)
1.32)判断字符是否是十六进制
2 数据结构:
API:
endsWith
startsWith
str.split("\.")(字符串的匹配) 转义字符
str.contains(ele)

5 最长回文子串(第三个答案)
找出字符串中最长的回文串

class Solution {
   
    public String longestPalindrome(String s) {
   
        if(s==null || s.length()==0){
   
            return "";
        }
        int left=0,right=0;
        //maxlen=0,不能等于1,因为当只有一个"a"时候,left要变成-1
        int len=1,maxlen=0,start=0;
        for(int cur=0;cur<s.length();cur++){
   
            left=cur-1;
            right=cur+1;
            //看左边或者右边哪一边和当前值相等
            while(left>=0 && s.charAt(left)==s.charAt(cur)){
   
                len++;
                left--;
            }
            while(right<s.length() && s.charAt(right)==s.charAt(cur)){
   
                len++;
                right++;
            }
            //看两侧是否相等
            while(left>=0 && right<s.length() && s.charAt(left)==s.charAt(right)){
   
                left--;
                right++;
                len+=2;
            }
            if(len>maxlen){
   
                maxlen=len;
                start=left;
            }
            len=1;
        }
        return s.substring(start+1,start+maxlen+1);
    }
}

1 思路 中心扩散算法
1)遍历字符串
2)定义5个变量 左指针,右指针 最大字符长度 字符串的长度(每次更新为1) 起始位置
3)看左边或者右边(单侧)是否和当前值相等,看左边和右边双侧是否和当前相等,依次扩散即可(借助找到最大的长度来保存)
2 数据结构与算法
API:str.substring(); str.charAt(i)

补充题目4:手撕快速排序

class Solution {
   
    public int[] sortArray(int[] nums) {
   
        quicksort(nums,0,nums.length-1);
        return nums;

    }
    public static void quicksort(int[] nums,int left,int right){
   
        int l=left,r=right;
        int base=nums[(l+r)/2];
        while(l<r){
   
            while(nums[l]<base){
   
                l++;
            }
            while(nums[r]>base){
   
                r--;
            }
            if(l>=r){
   
                break;
            }
            int temp=nums[l];
            nums[l]=nums[r];
            nums[r]=temp;
            if(base==nums[l]){
   
                r--;
            }
            if(base==nums[r]){
   
                l++;
            }
        }
//注意先左边后右边,并且此处只能是 == 不能是 >=  要不然会报错!!!!!!!!!!!!!!!!!!!!!
        if(l==r){
   
            l++;
            r--;
        }
        if(l<right){
   
            quicksort(nums,l,right);} 
        if(left<r){
   
            quicksort(nums,left,r);
        }
    }
}

1 思路
1)找到left 和right, 和基准值base
2) 左边坐标指向的元素和基准值进行比较,右边坐标指向的元素和基准值进行比较;比较完之后,判断是否索引越界等,否则进行交换
3)如果左边索引指向的元素等于基准值,右索引减一;如果右边索引指向的元素等于基准值,左索引加1
4)递归 :分成两部分(左、右),依次快排递归
2 数据结构
数组

1143 最长的公共子序列

//动态规划注意 边界条件即可
class Solution {
   
    public int longestCommonSubsequence(String text1, String text2) {
   
        int m=text1.length(),n=text2.length();
        int[][] dp=new int[m+1][n+1];
        //从第一个字母开始
        for(int i=1;i<dp.length;i++){
   
            char ch1=text1.charAt(i-1);
            for(int j=1;j<dp[0].length;j++){
   
                char ch2=text2.charAt(j-1);
                //若相等,对角线+1
                if(ch1==ch2){
   
                    dp[i][j]=dp[i-1][j-1]+1;
                }else{
   
                    //若不等,取先前相等的最大值
                    dp[i][j]=Math.max(dp[i-1][j],dp[i][j-1]);
                }
            }
        }
        return dp[m][n];
    }
}

1 思路
1)动态规划问题
2)两个字符串分别为两个坐标,但是多了一行一列,用i-1,j-1表示两个字符串中下标的元素
3)若相等,那么对角线+1;若不等,取左侧或者上侧的最大值

8 字符串转整数

class Solution {
   
    public int myAtoi(String s) {
   
        int flag = 1;
        int res = 0;
        int n = s.length();
        int i=0;
        while(i<n && s.charAt(i)==' '){
   i++;}
        if(i<n && s.charAt(i) == '-'){
   flag = -1;i++;}
        if(i<n && s.charAt(i) =='+'){
   
            //前边有负号,这边就不去
            if(flag == -1){
   
                return 0;
            }
            i++;}
        while(i<n && Character.isDigit(s.charAt(i))){
   
            int ch = s.charAt(i)-'0';
            if(res>Integer.MAX_VALUE/10 ||( res==Integer.MAX_VALUE/10 && ch> 7)){
   
                return flag>0?Integer.MAX_VALUE:Integer.MIN_VALUE;

            }
            res = res*10+ch;
            i++;

        }
        return flag>0?res:-res;
            }
}

1 思路
1)正常的字符串的遍历,先去掉空格,然后判断正负号,最后判断是否是数字
2)是数字的化要进行十进值的转换,中间要判断是否数字越界

718 最长重复子数组
同 1143 最长公共子子序列
第三个解法,动态规划解法

class Solution {
   
    public int findLength(int[] A, int[] B) {
   
        int m=A.length,n=B.length;
        int[][] dp=new int[m+1][n+1];
        int max=0;
        for(int i=1;i<dp.length;i++){
   
            for(int j=1;j<dp[0].length;j++){
   
                //注意是i-1
                int a=A[i-1];
                int b=B[j-1];
                if(a==b){
   
                    dp[i][j]=dp[i-1][j-1]+1;
                }
                //最后只需要求最大的长度
                max=Math.max(max,dp[i][j]);
            }
        }
        return max;
    }
}

1 思路
1)创建dp矩阵,相等的话对角线元素加1,不等设置为0
2)最后更新最大值
dp[i][j] 只依赖上一行上一列的对角线的值,所以我们从右上角开始计算。
一维数组 dp , dp[j] 是以 A[i-1], B[j-1] 为末尾项的最长公共子数组的长度
2 数据结构
数组

215 数组中的第K个最大元素

class Solution {
   
    public int findKthLargest(int[] nums, int k) {
   
        quickSort(nums,0,nums.length-1);
        return nums[nums.length-k];
    }
    public void quickSort(int[] arr,int left,int right){
   
        int l=left;
        int r=right;
        int base=arr[(l+r)/2];
        while(l<r){
   
            while(arr[l]<base){
   
                l++;
            }
            while(arr[r]>base){
   
                r--;
            }
            if(l>=r){
   
                break;
            }
            int temp=arr[l];
            arr[l]=arr[r];
            arr[r]=temp;
            if(arr[l]==base){
   
                r--;
            }
            if(arr[r]==base){
   
                l++;
            }
        }
        if(l==r){
   
            l++;
            r--;

        }
        if(l<right){
   
            quickSort(arr,l,right);
        }
        if(r>left){
   
            quickSort(arr,left,r);
        }
    }
}

1 思路
1)快排
2)返回第 nums.length-1 索引的元素

46 全排列
官方题解:视频讲解的很清楚
回溯算法(引申题目很多,要掌握),排列是讲究顺序的,无重复,无遗漏
广度优先遍历
深度优先遍历(有个回退的算法),递归函数,一定要考虑清楚每个变量

//官方视频解法
class Solution {
   
    public List<List<Integer>> permute(int[] nums) {
   
        int len=nums.length;
        List<List<Integer>> res=new LinkedList<List<Integer>>();
        if(len==0){
   
            return res;
        }
        //栈,走过的路径
        Deque
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值