leetcode1 两数之和
class Solution {
public int[] twoSum(int[] nums, int target) {
//map里面存储着遍历过的值和索引
HashMap<Integer,Integer>map = new HashMap<>();
for(int i =0;i<nums.length;i++){
//查看map中是否有和当前值配对的值,如果有返回结果如果没有,当前值扔进map
if(map.containsKey(target-nums[i])){
//返回并且创建int数组的方法
return new int[]{i,map.get(target-nums[i])};
}else{
map.put(nums[i],i);
}
}
return new int[2];
}
}
leetcode2 两数相加
class Solution {
//分析:逆序链表,非0开头,返回也是逆序。
//必须新建一个链表存结果,然后留意进位即可。
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
int add = 0;
ListNode cur = dummy;
//如果其中一个不为空,那就继续循环
while(l1!=null||l2!=null){
//如果是空就按0处理,求和不影响
int val1 = l1==null?0:l1.val;
int val2 = l2==null?0:l2.val;
int value = (val1+val2+add)%10;
//进位
add = (val1+val2+add)/10;
ListNode temp = new ListNode(value);
cur.next =temp;
cur=cur.next;
//如果是空了,不能后移,因为没有next指针
if(l1!=null) l1=l1.next;
if(l2!=null) l2=l2.next;
}
//循环出来之后,还有可能有一位进位
if(add!=0){
ListNode temp = new ListNode(add);
cur.next = temp;
}
return dummy.next;
}
}
leetcode3 无重复字符的最长子串
class Solution {
public int lengthOfLongestSubstring(String s) {
//分析:两个指针移动找到不重复的区间。
//用一个数组记录是否出现过,如果没有出现过,右指针正产后移,
//如果出现过,左指针右移把之前出现的位置移动到区间外,右指针正常后移
boolean charFlag[]= new boolean[128];
int left = 0,right = 1,res=0;
//这个逻辑对长度为0和1的都得特殊处理
if(s.length()==0)return 0;
//左指针一开始就在0,表示0位置的字符已经算进去了
charFlag[s.charAt(0)]=true;
//如果长度为1,right直接就退出去了
if(s.length()==1)return 1;
while(right<s.length()){
//如果可以右移,右移同时补充标记+更新res
if(charFlag[s.charAt(right)]==false){
charFlag[s.charAt(right)]=true;
res = Math.max(res,right-left+1);
right++;
//如果不能右移了。已经有重复了,左指针移动,
//把重复字符越过去,移动过程要更新标记数组
}else{
while(s.charAt(left)!=s.charAt(right)){
charFlag[s.charAt(left)]=false;
left++;
}
charFlag[s.charAt(left)]=false;
left++;
}
}
return res;
}
}
leetcode4 寻找两个有序数组的中位数
log(m+n)的时间复杂度。
分析:
一定要二分,每次要减少一半的元素。
所以只能比较两个元素的中位数,然后依据三种情况排除。
整体思路利用求第K小的数来思考。不断更新K,减少搜索空间。
尤其要关注边界条件。
leetcode5 最长回文子串
class Solution {
//分析:首先想到区间DP的思路
//先对区间长度遍历,然后对起点遍历,j=i+l。
//在循环过程中初始化dp数组。dp[i][j]表示i到j是否回文串。
//dp[I][J]=true 状态转移方程见下代码
public String longestPalindrome(String s) {
int size = s.length();
boolean [][] dp = new boolean[size][size];
String res="";
//区间dp固定两个循环
for(int l = 0;l<size;l++){
for(int i =0;i<size-l;i++){
int j =i+l;
//关于dp初始化l=0和l=1两种初始情况的初始化
//分别是奇数长度的初始状态和偶数长度的初始状态
if(l==0){
dp[i][j]=true;
}
else if(l==1){
if(s.charAt(i)==s.charAt(j)){
dp[i][j]=true;
}
}
//正常的DP状态转移方程,两端字符相等且中间一段已经是回文串
else{
if(dp[i+1][j-1]==true&&s.charAt(i)==s.charAt(j)){
dp[i][j]=true;
}
}
//更新结果,通过res的长度判断是否需要更新
if(dp[i][j]==true&&l+1>res.length()){
res=s.substring(i,j+1);
}
}
}
return res;
}
}
leetcode6 Z 字形变换
class Solution {
public String convert(String s, int numRows) {
//分析:需要n个StringBuilder保存中间内容
//需要完成index的更新
StringBuilder [] array = new StringBuilder[numRows];
//numRows==1需要特殊处理,在更新flag时有问题
if(numRows==1)return s;
//初始化数组
for(int i =0;i<numRows;i++){
array[i]=new StringBuilder();
}
//因为先更新index,后使用index,所以初始值为-1.保证第一个填入0的位置。
int index = -1;
boolean flag =true;
for(int i=0;i<s.length();i++){
//更新flag表示index增加还是减少
if(flag==true&&index==numRows-1){
flag=false;
}
if(flag==false&&index == 0){
flag=true;
}
//根据flag更新index
if(flag ==true){
index++;
}else{
index--;
}
//更新好index后把字符放入应该在的位置
array[index].append(s.charAt(i));
}
//构造结果
StringBuilder res = new StringBuilder();
for(int i =0;i<numRows;i++){
res.append(array[i]);
}
return res.toString();
}
}
leetcode7 整数反转
class Solution {
//分析:反转很简单,问题在于溢出
public int reverse(int x) {
//reverse保存要返回的结果
int reverse =0;
//想把整数转到负数统一处理,因为负数的范围大一些,最后再还原0
boolean flagChange = false;
if(x>0){
x=-x;
flagChange=true;
}
//开始反转
while(x<0){
int num = x%10;
x=x/10;
//预判一下要溢出了,返回0,一种是乘10就溢出,一种是乘10不溢出,
//但是加num就溢出了。
if(reverse<Integer.MIN_VALUE/10)return 0;
if(reverse==Integer.MIN_VALUE/10&&num<Integer.MIN_VALUE%10){
return 0;
}
reverse=reverse*10+num;
}
//还原符号
if(flagChange==true){
//还原的时候也有一个溢出的点,其实在上面也能处理掉,单独拉出来不容易遗忘
if(reverse==Integer.MIN_VALUE)return 0;
reverse=-reverse;
}
return reverse;
}
}
数月之后发现新的官方题解,简直是优雅到极致了
class Solution {
public int reverse(int x) {
int reverseNum = 0;
while(x!=0){
//此处有证明,不需要额外判断,因为最后一位小于7就可以,因为x本身也在32位范围内,所以最后一位其实是小于2的
if(reverseNum<Integer.MIN_VALUE/10||reverseNum>Integer.MAX_VALUE/10){
return 0;
}
int num = x%10;
x=x/10;
reverseNum =reverseNum*10+num;
}
return reverseNum;
}
}
leetcode8 字符串转换整数
leetcode9 回文数
class Solution {
//分析:还是按照整数反转的策略写,
//回文都是两种情况,奇数长度和偶数长度需要注意。
public boolean isPalindrome(int x) {
//特殊情况:x小于0,x以0结尾(且不是0)一定不是回文且走下面的逻辑可能出问题
if(x<0)return false;
if(x%10==0&&x!=0)return false;
int reverse = 0;
//反转过程
while(x>reverse){
int num = x%10;
x=x/10;
reverse=reverse*10+num;
}
//两种情况,偶数和奇数(如果以0结尾,会在这块判断出问题)
if(x==reverse||x==reverse/10)return true;
return false;
}
}
时隔数月再看这个题想到的解法
再reverse过程中比较就可以了。
x如果等于reverse或者x/10=reverse就可以
但是特殊情况多了一个,就是个位数的时候。
class Solution {
public boolean isPalindrome(int x) {
// 这几个特殊情况确实容易遗漏
if(x<0)return false;
if(x<10)return true;
if(x%10==0)return false;
int reverse = 0;
while(x>reverse){
int digit = x%10;
x=x/10;
reverse = reverse*10+digit;
if(x==reverse||x/10==reverse)return true;
}
return false;
}
}
leetcode 10 正则表达式匹配
leetcode 11 盛水最多的容器
class Solution {
public int maxArea(int[] height) {
int maxArea = 0;
int left =0,right =height.length-1;
while(left<right){
maxArea = Math.max(maxArea, (right-left)*Math.min(height[left],height[right]));
if(height[left]>=height[right]){
right--;
}else{
left++;
}
}
return maxArea;
}
}
leetcode 12 整数转罗马数字
class Solution {
public String intToRoman(int num) {
String[] keyTable = {"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
int [] valueTable = {1000,900,500,400,100,90,50,40,10,9,5,4,1};
StringBuilder res = new StringBuilder();
for(int i = 0;i<valueTable.length;i++){
if(num>=valueTable[i]){
num-=valueTable[i];
res.append(keyTable[i]);
i--;
}
}
return res.toString();
}
}
leetcode 13 罗马数转整数
class Solution {
public int romanToInt(String s) {
char[] keyTable = {'M','D','C','L','X','V','I'};
int [] valueTable = {1000,500,100,50,10,5,1};
HashMap<Character,Integer> vMap = new HashMap<>();
for(int i=0;i<keyTable.length;i++){
vMap.put(keyTable[i],valueTable[i]);
}
int ans = 0;
for(int i=0;i<s.length();i++){
if(i==s.length()-1){
ans += vMap.get(s.charAt(i));
}else if(vMap.get(s.charAt(i))>=vMap.get(s.charAt(i+1))){
ans += vMap.get(s.charAt(i));
}else{
ans -= vMap.get(s.charAt(i));
}
}
return ans;
}
}
leetcode14 最长公共前缀
class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs.length == 0)return "";
for(int i = 0;i<strs[0].length();i++){
for(int j = 1 ;j<strs.length;j++){
if(strs[j].length()<=i||strs[j].charAt(i)!=strs[0].charAt(i)){
return strs[0].substring(0,i);
}
}
}
return strs[0];
}
}
leetcode 15 三数之和
sort + 双指针
核心在不用set去重
外层保证i不会相同。
指定left的时候要i更新之后赋值。 保证i不会和left赋值重复。
每次更新res后,右移左指针要跳过所有相同的数字。
这样i不会相同,left不会相同,自然不会有相同结果。
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
List<List<Integer>> res = new LinkedList<>();
Arrays.sort(nums);
for(int i = 0 ;i<nums.length;i++){
int right = nums.length-1;
while(i!=0 && i<nums.length&& nums[i]==nums[i-1]) i++;
if(i==nums.length)return res;
int left = i+1;
while(left<right){
if(nums[i]+nums[left]+nums[right]==0){
List<Integer> temp = new LinkedList<>();
temp.add(nums[i]);
temp.add(nums[left]);
temp.add(nums[right]);
res.add(temp);
left++;
while(left<right&&nums[left]==nums[left-1])left++;
}else if((nums[i]+nums[left]+nums[right]<0)){
left++;
}else{
right--;
}
}
}
return res;
}
}
leetcode16 最接近的三数之和
class Solution {
public int threeSumClosest(int[] nums, int target) {
int res = nums[0]+nums[1]+nums[2];
Arrays.sort(nums);
for(int i = 0 ;i<nums.length;i++){
int right = nums.length-1;
int left = i+1;
while(left<right){
int sum = nums[i]+nums[left]+nums[right];
if(sum==target){
return target;
}else if(sum<target){
if(Math.abs(target - sum)<Math.abs(target-res)){
res = sum;
}
left++;
}else{
if(Math.abs(target - sum)<Math.abs(target-res)){
res = sum;
}
right--;
}
}
}
return res;
}
}```
## leetcode 17 电话号码字母组合
复习一下,DFS的恢复现场。
用String builder可以灵活增减char
```java
class Solution {
List<String> res = new LinkedList<>();
public List<String> letterCombinations(String digits) {
String[] table = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
if(digits.length()==0)return res;
search(table,0, new StringBuilder(), digits);
return res;
}
public void search(String[] table, int index, StringBuilder temp, String digits){
if(index == digits.length()){
res.add(temp.toString());
return ;
}
for(int i = 0;i< table[digits.charAt(index)-'0'].length();i++){
char ch = table[digits.charAt(index)-'0'].charAt(i);
temp.append(ch);
search(table,index+1, temp, digits);
temp.deleteCharAt(temp.length()-1);
}
}
}
leetcode 18 四数之和
注意剪枝
leetcode 19 删除链表的倒数第N个节点
这个题应该想到对head节点操作会有麻烦,所以dummy要用好。
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode fast = dummy;
ListNode slow = dummy;
while(n!=0){
fast = fast.next;
n--;
}
while(fast.next!=null){
fast = fast.next;
slow = slow.next;
}
slow.next = slow.next.next;
return dummy.next;
}