leetCode01-05
01-两数之和
给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。
你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。
你可以按任意顺序返回答案。
package LeetCodeHot100;
import java.util.*;
public class L01TwoNumSum {
/**
* 使用hashmap
* 由题目得不存在重复的答案
* @param nums
* @param target
* @return
*/
public int[] twoSum(int[] nums, int target) {
Map<Integer,Integer> map = new HashMap<>();
for (int i=0;i< nums.length;i++){
if (map.containsKey(target-nums[i])){
//map在以第一个
return new int[]{map.get(target-nums[i]),i};
}else {
map.put(nums[i], i);
}
}
throw new IllegalArgumentException("没有数相加等于target");
}
}
02-两数相加
给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。
请你将两个数相加,并以相同形式返回一个表示和的链表。
你可以假设除了数字 0 之外,这两个数都不会以 0 开头。
package LeetCodeHot100;
public class L02LinkNodeTwoNumSum {
/**
* 将两个链表看成是相同长度的进行遍历,如果一个链表较短则在前面补 0,
* 比如 987 + 23 = 987 + 023 = 1010
* 每一位计算的同时需要考虑上一位的进位问题,而当前位计算结束后同样需要更新进位值
* 如果两个链表全部遍历完毕后,进位值为 1,则在新链表最前方添加节点1
* 对于链表问题,返回结果为头结点时,通常需要先初始化一个预先指针 pre,
* 该指针的下一个节点指向真正的头结点head。
* 使用预先指针的目的在于链表初始化时无可用节点值,
* 而且链表构造过程需要指针移动,进而会导致头指针丢失,无法返回结果。
* @param l1
* @param l2
* @return
*/
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
//预设节点,防止移动过程中头指针丢失
ListNode pre = new ListNode(0);
ListNode cur = pre;
int carry = 0;
while (l1!=null||l2!=null){
//当l1或者l2为空时,补0
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 = 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;
}
}
03-无重复字符串的最长子串
给定一个字符串,请你找出其中不含有重复字符的 最长子串 的长度。
package LeetCodeHot100;
import java.util.HashMap;
import java.util.Map;
public class L03NoRepeatString {
/**
* 滑动窗口
* 定义一个 map 数据结构存储 (k, v),其中 key 值为字符,
* value 值为字符位置 +1,加 1 表示从字符位置后一个才开始不重复
* 我们定义不重复子串的开始位置为 start,结束位置为 end
* 随着 end 不断向后遍历,会遇到与 [start, end] 区间内字符相同的情况,
* 此时将字符作为 key 值,获取其 value 值,并更新 start,此时 [start, end] 区间内不存在重复字符
* 无论是否更新 start,都会更新其 map 数据结构和结果 max。
* @param s
* @return
*/
public int lengthOfLongestSubstring(String s) {
int length = s.length();
int max = 0;
Map<Character,Integer> map = new HashMap<>();
for (int start = 0,end =0;end<length;end++){
char element = s.charAt(end);
if (map.containsKey(element)){
//map.get()的地方进行+1操作
//存在就更新start的位置
//这里取start的最大值的原因是,如果后面两个字母重复的话,不取最大值可能会导致start回退
//如 a.. b..a...a...b
//当到第二个a的时候,start=3,下一步到第二个b,如果start = map.get(b)+1 = 2 ,可见start由3回退到2了
start = Math.max(map.get(element)+1,start);
}
//更新最大不重复字符串的值
max = Math.max(max,end-start+1);
//放入最新的字符
map.put(element,end);
}
return max;
}
}
04-
暂无
05-最长回文子串
给你一个字符串 s,找到 s 中最长的回文子串。
示例 1:
输入:s = “babad” 输出:“bab” 解释:“aba” 同样是符合题意的答案。
示例 2:输入:s = “cbbd” 输出:“bb”
package LeetCodeHot100;
public class L05LongestPalindrome {
/**
* 动态规划的状态转移方程:
* dP(i, j) = dP(i+1, j-1)∧ (S_i == S_j)
* 也就是说,只有s[i+1:j−1] 是回文串,
* 并且 s 的第 i 和 j 个字母相同 s[i:j] 才会是回文串
* 上文的所有讨论是建立在子串长度大于 2 的前提之上的,我们还需要考虑
* 动态规划中的边界条件,即子串的长度为 1 或 2。对于长度为 1 的子串,
* 它显然是个回文串;对于长度为 2 的子串,只要它的两个字母相同,它就是一个回文串。
*边界条件:
* dP(i,i)=true
* dP(i,i+1)=(Si==Si+1)
* 最终的答案即为所有dP(i,j)=true 中 j-i+1(即子串长度)的最大值
* @param s
* @return
*/
//------------------------------------------------------------------------------
//dp[i][j]表示当前子字符串,i到j是否是回文字符串::
//状态转移方程式::dp[i][j] = dp[i+1][j-1]&&(ch[i]==ch[j])
//边界条件 由状态转移方程,,子字符串至少需要三个字符:
// 只有一个字符 dp[i][i] = true,,两个字符::dp[i][i+1] = ch[i]==ch[i+1]
public String longestPalindrome(String s) {
if(s==null||s.length()==0) return "";
if(s.length()==1) return s;
char[] ch = s.toCharArray();
int len = ch.length;
int[] ans = new int[2];
boolean[][] dp = new boolean[len][len];
int maxlength = 1;
//j相当于右边界,每次求子串[0,j]的最长回文子串
for(int j=0;j<len;j++){
for(int i=0;i<j;i++){
//包含了边界处理
dp[i][j] = (ch[i]==ch[j])&&(j-i<3||dp[i+1][j-1]);
//如果此子区间是回文串,则看是否更长,是则更新
if(dp[i][j]&&maxlength<j-i+1){
maxlength = j-i+1;
ans[0] = i;
ans[1] = j;
}
}
}
return s.substring(ans[0],ans[1]+1);
}
}