前期做题,跳过困难的。
1. 两数之和 :(简单)
方法一:暴力解法
简单采用循环进行遍历
使用两层for循环
class Solution {
public static int[] twoSum(int[] nums, int target) {
int[] arr=new int[2];
int i=0;
for(i=0;i<nums.length;i++){
//循环
//1.记住第一个数字
int tmp1=nums[i];
int target1=i;
for(int j=i+1;j<nums.length;j++){
int tmp2=nums[j];
int target2=j;
if(tmp2+tmp1==target){
arr[0]=target1;
arr[1]=target2;
return arr;
}
}
}
return null;
}
}
运行结果:
时间复杂度:O(N^2),N为数组的长度
空间复杂度:O(1),只用到常数个临时变量
方法二:查找表(没有想到这个方法)
java文档建议在初始hash表时确定容量,以避免消耗
时间复杂度:O(n),这里n为数组的长度。
空间复杂度:0(n),哈希表里最多需要存n-1个键值对
运行结果:
2.两数相加(中等)
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
输入:l1 = [2,4,3], l2 = [5,6,4] 输出:[7,0,8] 解释:342 + 465 = 807.
思路:
从头开始遍历的话,
其实就是从个位数开始相加,
相加后需要mod10为此时位数上的数
同时需要进位
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
//两个相同的头节点
//一个遍历
//一个不动
ListNode pre=new ListNode(0);
ListNode cur=pre;
int carry=0;
//遍历两条链表
//直到两条链表都为空时才完成循环
//这个操作就相当于从个位数起开始相加
while(l1!=null || l2!=null){
//问号表达式
//A?B:C
int x=l1==null?0:l1.val;
int y=l2==null?0:l2.val;
int sum=x+y+carry;
//进位
carry=sum/10;
sum=sum%10;
cur.next=new ListNode(sum);//构造一个节点
cur=cur.next;
if(l1!=null){
l1=l1.next;
}
if(l2!=null){
l2=l2.next;
}
}
if(carry>=1){
cur.next=new ListNode(carry);
}
return pre.next;
}
}
3.无重复字符的最长子串
题目链接:3. 无重复字符的最长子串 - 力扣(LeetCode)
给定一个字符串 s
,请你找出其中不含有重复字符的 最长子串的长度。
思考:什么数组不能存入重复的元素。
maybe hashset
set用于存放不重复的数据
有点忘了有关和string的相关操作
class Solution3 {
public static int lengthOfLongestSubstring(String s) {
Set<Character> set=new HashSet<>();
for(int i=0;i<s.length();i++){
char ch=s.charAt(i);
set.add(ch);
}
return set.size();
}
}
不通过,经过检查看错题目的含义了。
方法一:暴力求解
自己的想法
class Solution4 {
public static int lengthOfLongestSubstring(String s) {
Set<Character> set=new HashSet<>();
int save=0;
for(int i=0;i<s.length();i++){
//遍历每一个子串
int count=0;
char ch=s.charAt(i);
set.add(ch);
count++;
for(int j=i+1;j<s.length();j++){
ch=s.charAt(j);
//如果添加失败就意味着当前set存入的字符串是一组不重复的字符串
//直到后面的添加操作成功时才可以进入一个新的子字符串,重新进行相应的操作
//此时就可以比较每一次子串的长度,返回最长的长度
if(set.add(ch)){
count++;
}else {
break;
}
}
if(save<count){
save=count;
}
set.clear();
}
return save;
}
}
方法二:滑动窗口及优化
class 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;
}
}
作者:力扣官方题解
链接:https://leetcode.cn/problems/longest-substring-without-repeating-characters/solutions/227999/wu-zhong-fu-zi-fu-de-zui-chang-zi-chuan-by-leetc-2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
// 方法二:滑动窗口
int n = s.length();
if (n <= 1) {
return n;
}
int l = 0, r = 1;
HashSet<Character> set = new HashSet<>();
set.add(s.charAt(l));
int res = 0;
while (r < n) {// 进入循环
while (r < n && !set.contains(s.charAt(r))) {
set.add(s.charAt(r));
r++;
}
res = Math.max(res, r - l);
set.remove(s.charAt(l));
l++;
}
return res;
4.最长回文字符串
给你一个字符串 s
,找到 s
中最长的 回文子串。
方法一:暴力求解
方法二:中心扩散法
方法三:动态规划法
class Solution {
public String longestPalindrome(String s) {
int len=s.length();
//左边界和右边界及右-左的长度
int left=0;
int right=0;
int res=0;
boolean[][] dp=new boolean[len][len];
//判断每个边界框是否为true,选择最长的即可
//一列一列的填写
for(int i=len-1;i>=0;i--){ //最右侧的内容,列
for(int j=i;j<len;j++){//最左侧的内容,行
//为true的情况
//1.为对角线或只有3个字符的时候,则必为字符串
//2.当判断外层的两部分为相同时,需要判断内部也是true其整体才是回文字符串
if(s.charAt(i)==s.charAt(j)&&((j-i<=2||dp[i+1][j-1]))){
dp[i][j]=true;
if(j-i>res){
res=j-i;
left=i;
right=j;
}
}
}
}
return s.substring(left,right+1);//左闭右开
}
}
题目五:Z字形变化
方法一:利用二维矩阵模拟
//直接构造二维矩阵
//此时需要直到一共要n*m的具体数值
//建立对应的关系
13.Java之String 类_java string[] 键-CSDN博客
StringBuffer和StringBuilder区别详解(Java面试)_stringbuffer和stringbuilder有什么区别-CSDN博客
class Solution {
public static String convert(String s, int numRows) {
int len=s.length();
//直接返回的情况
if(len<=1||numRows<=1||len<=numRows){
return s;
}
//numrows就是矩阵的行
//我们观察Z,当numrows为r时,可以看出一个Z需要占用2*r+(r-2)
//1.需要r
//2.后面的每个其实是t=2r-2
//3.所以需要占用的列是r-1
//因此我们有[len/t]个周期
// (最后一个周期视作完整周期)
//一个需要[len/t]*(r-1)
int t=2*numRows-2;
int c=((len+t-1)/t)*(numRows-1);
char[][] arr=new char[numRows][c];
for(int i=0,x=0,y=0;i<len;++i){
arr[x][y]=s.charAt(i);
//向下移动
if(i%t<numRows-1){
++x;
}else {
--x;
++y;
}
}
StringBuffer st=new StringBuffer();
for(char[] row:arr){
for(char ch:row){
if(ch!=0){
st.append(ch);
}
}
}
return st.toString();
}
}
方法二:压缩矩阵空间
方法一中的矩阵有大量的空间没有被使用,能否优化呢?
注意到每次往矩阵的某一行添加字符时,都会添加到该行上一个字符的右侧,且最后组成答案时只会用到每行的非空字符。因此我们可以将矩阵的每行初始化为一个空列表,每次向某一行添加字符时,添加到该行的列表末尾即可。
作者:力扣官方题解
链接:https://leetcode.cn/problems/zigzag-conversion/solutions/1298127/z-zi-xing-bian-huan-by-leetcode-solution-4n3u/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
复杂度分析
时间复杂度:O(n)O(n)O(n)。
空间复杂度:O(n)O(n)O(n)。压缩后的矩阵需要 O(n)O(n)O(n) 的空间
class Solution {
public static String convert(String s, int numRows) {
int n=s.length(),r=numRows;
if(r==1||r>=n){
return s;
}
StringBuffer[] mat=new StringBuffer[r];
for(int i=0;i<r;i++){
mat[i]=new StringBuffer();
}
for(int i=0,x=0,t=2*r-2;i<n;i++){
mat[x].append(s.charAt(i));
if(i%t<r-1){//每一个数组框其实代表着每一行所需要打印的数据
++x;
}else{
--x;
}
}
StringBuffer ans=new StringBuffer();
for(StringBuffer row:mat){
ans.append(row);
}
return ans.toString();
}
}
//构造了一个数组
//这个数组的每一个数组框代表着每一行需要打印的字符串