官方代码均来自力扣力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台
给定一个整数数组 nums
和一个整数目标值 target
,请你在该数组中找出 和为目标值 target
的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
我的代码:
暴力枚举,通过两次循环,枚举数组,寻找target-i
class Solution {
public int[] twoSum(int[] nums, int target) {
for(int i =0;i
官方优解:
使用哈希表,根据题目要求只需找出一组结果,那么就遍历一遍数组,每存一个数x判断哈希表中是否存在target-x,如果没有就将x存入哈希表,如果有就直接返回new数组返回target-x和x。
class Solution {
public int[] twoSum(int[] nums, int target) {
Map hashtable = new HashMap();
for (int i = 0; i < nums.length; ++i) {
if (hashtable.containsKey(target - nums[i])) {
return new int[]{hashtable.get(target - nums[i]), i};
}
hashtable.put(nums[i], i);
}
return new int[0];
}
}
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
根本没做出来,不会。直接上官方题解,看代码注释。
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode pre = new ListNode(0);
//创建完预先指针 需要一个移动指针来遍历链表
ListNode cur = pre;
//开始遍历两个链表 当两个链表都是空值时停止循环
int carry=0;//carry是全局变量 需要while循环外判断最后是否进位
while (l1!=null||l2!=null){
//定义int类型保存两个结点相加的数据 sum表示和 carry表示进位
int x =l1==null?0:l1.val;//需要判断此时结点是否为空值 为空的话就需要给0 不为空即value值
int y =l2==null?0:l2.val;
int sum = x+y+carry;
carry=sum/10;//存进位
sum=sum%10;//存和
cur.next = new ListNode(sum);//创建第三条链表的求和结点 并把结点地址保留给当前结点的next地址
cur=cur.next;//移动指针
if(l1!=null){
l1=l1.next;
}
if(l2!=null){
l2=l2.next;
}
}
//如果最后的进位是1 就要再创建一个新结点存1
if(carry==1){
cur.next=new ListNode(1);
}
//体现预先指针的作用了 因为移动指针会使结点地址丢失 所以用预先指针用next指向头节点的地址
return pre.next;
}
}
给定一个字符串 s
,请你找出其中不含有重复字符的 最长子串 的长度。
我的代码:
class Solution {
public static int lengthOfLongestSubstring(String s) {
char[] chars = s.toCharArray();//拆分字符串 获取字符数组
HashSet hashSet = new HashSet();//用set集合去重 找到所有不重复的元素 这时set的size就是长度的可能最大值
for (char aChar : chars) {
hashSet.add(aChar);
}//将字符数组存入set集合
int time ;//定义变量保存需要遍历size的次数
if("".equals(s)){
return 0;
}//空字符串直接返回0
//因为此时无法重复的字串长度 最大就是size 所以外循环就从size开始逐渐缩小一
//内循环就从字符数组的第一个字符开始每次截取字符串的size长度
//只需要遍历到数组长度-size长度的数组下标停止
//在内循环中 再用set集合去一次重 如果新set集合的size和截取的字符串长度不一样 那么就说明此次截取的字符串里有重复字符 不符合要求
//相反 如果长度一样 就说明截取的字符串就是最长的无重复字符的字串
for(time=hashSet.size();time>0;time--){
for(int i=0;i<=s.length()-time;i++){
char[] chars1 = s.substring(i, i + time ).toCharArray();
HashSet hashSet1 = new HashSet();
for (char c : chars1) {
hashSet1.add(c);
}
System.out.println(hashSet1.toString());
if(hashSet1.size()!=time){
}else if(hashSet1.size()==time){
return hashSet1.size();
}
}
}
return 1;
}
}
官方代码: 运用滑动窗口(双指针算法)
class Solution {
public int lengthOfLongestSubstring(String s) {
// 哈希集合,记录每个字符是否出现过
Set occ = new HashSet();
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;
}
}
给定两个大小分别为 m
和 n
的正序(从小到大)数组 nums1
和 nums2
。请你找出并返回这两个正序数组的 中位数 。
算法的时间复杂度应该为 O(log (m+n))
。
我的代码:两个数组存入第三个数组 再用冒泡排序排顺序算中位数
class Solution {
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
int nums3[] = new int[nums1.length+nums2.length];
for (int i=0;inums3[j+1]){
max=nums3[j];
nums3[j]=nums3[j+1];
nums3[j+1]=max;
}
}
}
double result=0;
if(nums3.length%2==0){
result = (nums3[nums3.length/2-1]+nums3[nums3.length/2])/2.0;
}else if(nums3.length%2!=0){
result= (nums3[nums3.length/2]);
}
return result;
}
}
官方代码:
class Solution {
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
if(nums1.length>nums2.length){
int temp[]=nums1;
nums1=nums2;
nums2=temp;
}//nums1为长度小的数组 nums2为长度大的数组
int m=nums1.length;
int n=nums2.length;
int size = (m+n+1)/2;//定义分割线左边的元素数量 不用讨论奇偶性 奇数左边多一 偶数一样
int left=0;//起始左边
int right=m;//起始右边 (需要遍历nums1数组防止越界)
while(leftnums2[j]){//分割线nums1左边元素大于nums2右边元素的话 就缩小找下一个区间[0,right(i-1)]
right=i-1;
}else{//找到了的话就让left等于查找到的i下标(也就是分割线的位置)
left=i;
}
}
int i=left;//(上分割线下标)
int j=size-i;//(下分割线下标)
int nums1LeftMax=i==0?Integer.MIN_VALUE:nums1[i-1];//(nums1分割线左边如果没有数就取整型最小 让他在下面比较函数中不会被选择)
int nums1RightMax=i==m?Integer.MAX_VALUE:nums1[i];//(nums1分割线右边如果没有数就取整型最大 让他在下面比较函数中不会被选择)
int nums2LeftMax=j==0?Integer.MIN_VALUE:nums2[j-1];;//(nums2分割线左边如果没有数就取整型最小 让他在下面比较函数中不会被选择)
int nums2RightMax=j==n?Integer.MAX_VALUE:nums2[j];//(nums2分割线右边如果没有数就取整型最大 让他在下面比较函数中不会被选择)
if((m+n)%2==1){//判断奇偶性 奇数比较nums1和nums2左边最大的数 返回最大值
return Math.max(nums1LeftMax,nums2LeftMax);
}else {//偶数比较左边两数组最大和右边两数最小 求平均值返回
return (double)(Math.max(nums1LeftMax,nums2LeftMax)+Math.min(nums1RightMax,nums2RightMax))/2;
}
}
}
给你一个字符串 s
,找到 s
中最长的回文子串。
如果字符串的反序与原始字符串相同,则该字符串称为回文字符串
我的代码: 暴力解法,两层循环 如果i和j相等 把里面的字符串反转 如果反转后的字符串和原字符串一样 就存长度和截取字符串 遍历所有的情况找最长的回文子串 学会了一种方法就是用stringbuilder的反转方法然后通过string里面的contentequals方法和stringbuilder比较内容是否相同。
public static String longestPalindrome(String s) {
String rs = null;
int max =0;
int flag=0;
for (int i = 0; i < s.length(); i++) {
for(int j=s.length()-1;j>i;j--) {
if(s.charAt(i) == s.charAt(j)){
if (s.substring(i, j+1).contentEquals((new StringBuilder(s.substring(i, j+1)).reverse())) && s.substring(i, j+1).length() > max) {
max = s.substring(i, j+1).length();
rs = s.substring(i, j+1);
flag=1;
}
}
}
}
if(flag==0){
return s.substring(0,1);
}
return rs;
}
官方代码:动态规划dp数组 学了好长时间才能看懂
class Solution {
public static String longestPalindrome(String s) {
if(s.length()<2){
return s;
}
char chars[] = s.toCharArray();
boolean dp[][] = new boolean [s.length()][s.length()];//动态规划dp数组
int maxlength=1;//回文子串最大长度
int begin=0;//最长回文子串起始下标
for(int i=0;imaxlength){//如果是回文子串并且大于之前长度 那么就记录长度和下标
maxlength=j-i+1;
begin=i;
}
}
}
return s.substring(begin,begin+maxlength);//截取字符串 返回最长回文子串
}
}
将一个给定字符串 s
根据给定的行数 numRows
,以从上往下、从左到右进行 Z 字形排列。
比如输入字符串为 "PAYPALISHIRING"
行数为 3
时,排列如下:
P A H N A P L S I I G Y I R
之后,你的输出需要从左往右逐行读取,产生出一个新的字符串,比如:"PAHNAPLSIIGYIR"
。
请你实现这个将字符串进行指定行数变换的函数:
string convert(string s, int numRows);
我的代码: 一开始理解二维数组以为x就是横坐标 y就是纵坐标 其实不然
x表示行数 y表示列数 不过我用xy横纵坐标一个个往里填数 暴力求解
class Solution {
public static String convert(String s, int numRows) {
int n = 0;
int flag = 0;
int j = 0;
int ii = 0;
char chars[][] = new char[numRows][s.length()];
if (numRows == 1) {
return s;
} else if (numRows == 2) {
while (n < s.length()) {
for(int x=0;x=s.length()){
break;
}
chars[y][x]=s.charAt(n);
n++;
}
}
}
} else {
while (n < s.length()) {
if (flag == 0) {
for (int i = 0; i < numRows; i++) {
if (n == s.length()) {
break;
}
chars[i][j] = s.charAt(n);
ii = i;
n++;
flag = 1;
}
j++;
} else if (flag == 1) {
if (ii - 1 == 1) {
chars[ii - 1][j] = s.charAt(n);
j++;
n++;
flag = 0;
} else if (ii - 1 != 1) {
chars[ii - 1][j] = s.charAt(n);
j++;
n++;
ii--;
flag = 1;
}
}
}
}
String ss = "";
for (int x = 0; x < numRows; x++) {
for (int y = 0; y < s.length(); y++) {
if (chars[x][y] != '\u0000') {
ss = ss + "" + chars[x][y];
}
}
}
return ss;
}
}
官方代码: 先找规律 将变换字符转化为周期问题 设行数numRow就是r 那么一个周期填的字符就是r+r-2个 填的列数为r-1
class Solution {
public static String convert(String s, int numRows) {
int n=s.length();
int r=numRows;
if(r>=n||r==1){//如果只有一行或者字符串长度小于行数 直接返回字符串
return s;
}
int t=r+r-2;//求一个周期有多少字符
int c=(n+t-1)/t*(r-1);//求一共有多少列 用周期*每个周期列数 (n+t-1)可以确保最后一个不完整的周期也算一个周期
char mat[][] = new char[r][c];
for(int i=0,x=0,y=0;i
给你一个 32 位的有符号整数 x
,返回将 x
中的数字部分反转后的结果。
如果反转后整数超过 32 位的有符号整数的范围 [−231, 231 − 1]
,就返回 0。
假设环境不允许存储 64 位整数(有符号或无符号)。
我的代码: 纯是一坨 转来转去没什么意义
class Solution {
public static int reverse(int x) {
String s = String.valueOf(x);
StringBuilder sb = new StringBuilder(s);
long n;
int i;
if(sb.charAt(0)=='-'){
sb.deleteCharAt(0);
StringBuilder reverse = sb.reverse();
String sb1 = "-"+reverse;
n = Long.parseLong(sb1);
}else {
StringBuilder reverse = sb.reverse();
String sb1=reverse+"";
n = Long.parseLong(sb1);
}
if(n>2147483647||n<-2147483648)
{
return 0;
}else{
i=(int)n;
}
return i;
}
}
官方代码:
class Solution {
public static int reverse(int x) {
int rev =0;//反转的整数
int last=0;//末尾数字
while(x!=0){//算完最后一位截止
last=x%10;//求末尾数字
x=x/10;//每次循环去一位
if(rev>Integer.MAX_VALUE/10||rev
请你来实现一个 myAtoi(string s)
函数,使其能将字符串转换成一个 32 位有符号整数(类似 C/C++ 中的 atoi
函数)。
函数 myAtoi(string s)
的算法如下:
0
。必要时更改符号(从步骤 2 开始)。[−2^31, 2^31 − 1]
,需要截断这个整数,使其保持在这个范围内。具体来说,小于 −2^31
的整数应该被固定为 −2^31
,大于 2^31 − 1
的整数应该被固定为 2^31 − 1
。我的代码:还是纯纯滴一坨屎
class Solution {
public static int myAtoi(String s) {
String ns = s.trim();
int pflag=0;
int rflag=0;
int flag=0;
int x=0;//chars1下标
String ls="" ;//去零前的字符串
String dls="" ;//去零后的字符串
int n=0;//返回的int
char[] chars = ns.toCharArray();
char[] chars1 = new char[chars.length];
char[] chars2 = new char[chars1.length];
ArrayList list1 = new ArrayList();//去0集合
for(int i=0;i47&&chars[i]<58||(chars[i]==43)||chars[i]==45){
if(chars[i]==43){
if(chars1[0]!='\u0000'){
break;
}
ls="+";
pflag++;
continue;
}else if(chars[i]==45){
if(chars1[0]!='\u0000'){
break;
}
ls="-";
rflag++;
continue;
}
chars1[x]=chars[i];
x++;
}else{
break;
}
}
if(rflag>1||pflag>1||(rflag==1&&pflag==1)){
return 0;
}
for (char c : chars1) {
ls=ls+c;
}
ls=ls.trim();
chars2 = ls.toCharArray();
for (char c : chars2) {
list1.add(c);
}
int size = list1.size();
for(int i=0;i11){
if(dls.charAt(0)=='-'){
return -2147483648;
}else{
return 2147483647;
}
}
dls=dls.trim();
if(dls.equals("")){
return 0;
}
long l = Long.parseLong(dls);
if(l>2147483647){
return 2147483647;
}else if(l<-2147483648){
return -2147483648;
} else{
n=(int) l;
}
return n;
}
}
官方代码:
package leetcode.onetoten;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
class Eighth {
public static void main(String[] args) {
String s = "+-42";
System.out.println(myAtoi(s));
}
public static int myAtoi(String s) {
int n=s.length();
int index=0;
int sign =1;
int res=0;
while(indexInteger.MAX_VALUE/10||(res==Integer.MAX_VALUE/10&&last>7)){//越界处理
return sign==1?Integer.MAX_VALUE:Integer.MIN_VALUE;
}else{//推入处理
res =res*10+last;
index++;
}
}else{
break;
}
}
return res*sign;
}
}
另一种方法:自动机 就是一个个字符传进去在自动机里面判断 挺好理解 就是里面的hashmap初始化用了双大括号初始化 是匿名内部类的一种方法 一开始看了好久没看懂 也就这个比较难理解
用字符来判断状态 然后通过状态改变自动机里面的属性
class Solution {
public int myAtoi(String str) {
Automaton automaton = new Automaton();
int length = str.length();
for (int i = 0; i < length; ++i) {
automaton.get(str.charAt(i));
}
return (int) (automaton.sign * automaton.ans);
}
}
class Automaton {
public int sign = 1;
public long ans = 0;
private String state = "start";
private Map table = new HashMap() {{
put("start", new String[]{"start", "signed", "in_number", "end"});
put("signed", new String[]{"end", "end", "in_number", "end"});
put("in_number", new String[]{"end", "end", "in_number", "end"});
put("end", new String[]{"end", "end", "end", "end"});
}};
public void get(char c) {
state = table.get(state)[get_col(c)];
if ("in_number".equals(state)) {
ans = ans * 10 + c - '0';
ans = sign == 1 ? Math.min(ans, (long) Integer.MAX_VALUE) : Math.min(ans, -(long) Integer.MIN_VALUE);
} else if ("signed".equals(state)) {
sign = c == '+' ? 1 : -1;
}
}
private int get_col(char c) {
if (c == ' ') {
return 0;
}
if (c == '+' || c == '-') {
return 1;
}
if (Character.isDigit(c)) {
return 2;
}
return 3;
}
}
给你一个整数 x
,如果 x
是一个回文整数,返回 true
;否则,返回 false
。
回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
121
是回文,而 123
不是我的代码: 没用数学办法 用的builder里面的翻转求得
class Solution {
public static boolean isPalindrome(int x) {
StringBuilder stringBuilder = new StringBuilder();
int i=0;
int n=x;
if(x<0){
return false;
}
while(x/10!=0){
i=x%10;
x=x/10;
stringBuilder.append(i);
}
stringBuilder.append(x);
long l = Long.parseLong(String.valueOf(stringBuilder));
if(l==n){
return true;
}else {
return false;
}
}
}
官方代码: 给的代码解释通俗易懂 挺简单的
class Solution {
public boolean isPalindrome(int x) {
// 特殊情况:
// 如上所述,当 x < 0 时,x 不是回文数。
// 同样地,如果数字的最后一位是 0,为了使该数字为回文,
// 则其第一位数字也应该是 0
// 只有 0 满足这一属性
if (x < 0 || (x % 10 == 0 && x != 0)) {
return false;
}
int revertedNumber = 0;
while (x > revertedNumber) {
revertedNumber = revertedNumber * 10 + x % 10;
x /= 10;
}
// 当数字长度为奇数时,我们可以通过 revertedNumber/10 去除处于中位的数字。
// 例如,当输入为 12321 时,在 while 循环的末尾我们可以得到 x = 12,revertedNumber = 123,
// 由于处于中位的数字不影响回文(它总是与自己相等),所以我们可以简单地将其去除。
return x == revertedNumber || x == revertedNumber / 10;
}
}
给你一个字符串 s
和一个字符规律 p
,请你来实现一个支持 '.'
和 '*'
的正则表达式匹配。
'.'
匹配任意单个字符'*'
匹配零个或多个前面的那一个元素所谓匹配,是要涵盖 整个 字符串 s
的,而不是部分字符串。
示例 1:
输入:s = "aa", p = "a" 输出:false 解释:"a" 无法匹配 "aa" 整个字符串。
示例 2:
输入:s = "aa", p = "a*" 输出:true 解释:因为 '*' 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 'a'。因此,字符串 "aa" 可被视为 'a' 重复了一次。
示例 3:
输入:s = "ab", p = ".*" 输出:true 解释:".*" 表示可匹配零个或多个('*')任意字符('.')。
提示:
1 <= s.length <= 20
1 <= p.length <= 20
s
只包含从 a-z
的小写字母。p
只包含从 a-z
的小写字母,以及字符 .
和 *
。*
时,前面都匹配到有效的字符一开始做不会dp 用自己脑子想情况太多做不出来 实在是无力 直接看官方代码
这道题最坑的地方感觉是在玩文字游戏 *号匹配0个一个和多个的时候是可以包括*前面的字符的
也就是说 c*可以是0个字符也可以是c也可以是多个c
看b站视频讲的清楚一些 推荐这个up主【剑指Offer最优解】19. 正则表达式匹配 | 估计虐了不少人_哔哩哔哩_bilibili
官方代码:
class Solution {
public boolean isMatch(String s, String p) {
if(s==null||p==null){
return true;
}
int n =s.length();
int m =p.length();
boolean dp[][] = new boolean[n+1][m+1];
dp[0][0]=true;
for(int j=2;j<=m;j++){
if(p.charAt(j-1)=='*'){
dp[0][j]=dp[0][j-2];
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(p.charAt(j-1)!='*'){
if(p.charAt(j-1)=='.'||p.charAt(j-1)==s.charAt(i-1)){
dp[i][j]=dp[i-1][j-1];
}
}else{
if(p.charAt(j-2)!=s.charAt(i-1)&&p.charAt(j-2)!='.'){
dp[i][j]=dp[i][j-2];
}else{
dp[i][j]=dp[i][j-1]||dp[i-1][j]||dp[i][j-2];
}
}
}
}
return dp[n][m];
}
}