前三页 除了加星 其他都做了 第四页未看
没时间了,就不要把时间放在强迫症上,有重点的做题和复习,毕竟时间有限
注意:
不能草率省事,思路一定要自己写,准确的复述一遍,记得更深刻
刷透了,一定要刷够中等题不要抱着侥幸的想法
中等题一定要刷熟练,手撕腾讯三面(全排列)和快手一面(图像的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