bj_LeetCode刷题笔记
目录
- LeetCode刷题笔记
- LeetCode1.两数之和
- LeetCode2.两数相加
- LeetCode7.整数反转
- LeetCode9.回文数
- LeetCode13.罗马数字转整数
- LeetCode14.最长公共前缀
- LeetCode20.有效的括号
- LeetCode21.合并两个有序链表
- LeetCode26.删除排序数组中的重复项
- LeetCode121. 买卖股票的最佳时机
- LeetCode122. 买卖股票的最佳时机II
- 解法一:谷峰法
- 解法二:连续爬坡
LeetCode刷题笔记
LeetCode1.两数之和
给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。
你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
//利用Hashmap存储(key,value)=(值,索引) class Solution { public int[] twoSum(int[] nums, int target) { int[] newNums = new int[2]; Map<Integer, Integer> map = new HashMap(); for(int i = 0; i < nums.length ;i++) { int diff = target - nums[i]; if(map.get(diff) != null) { newNums[1] = i; newNums[0] = map.get(diff); return newNums; } map.put(nums[i], i); } return newNums; } }
LeetCode2.两数相加
给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
如果,我们将这两个数相加起来,则会返回一个新的链表来表示它们的和。
您可以假设除了数字 0 之外,这两个数都不会以 0 开头。
示例:
输入:(2 -> 4 -> 3) + (5 -> 6 -> 4)
输出:7 -> 0 -> 8
原因:342 + 465 = 807
/** * Definition for singly-linked list. * public class ListNode { * int val; //链表结点存储值 * ListNode next; //指向下一个结点 * ListNode(int x) { val = x; } //构造函数 * } */ class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { ListNode dummyHead = new ListNode(0); //头结点值为0 ListNode p = l1, q = l2, curr = dummyHead; int carry = 0; while (p != null || q != null) { int x = (p != null) ? p.val : 0; int y = (q != null) ? q.val : 0; int sum = carry + x + y; carry = sum / 10; curr.next = new ListNode(sum % 10); //最终结果为8070,去掉头结点 curr = curr.next; if (p != null) p = p.next; if (q != null) q = q.next; } if (carry > 0) { curr.next = new ListNode(carry); } return dummyHead.next; //返回去掉头结点之后的值,即807 } }
LeetCode7.整数反转
给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
示例 1:
输入: 123
输出: 321
示例 2:
输入: -123
输出: -321
示例 3:
输入: 120
输出: 21
注意:
假设我们的环境只能存储得下 32 位的有符号整数,则其数值范围为 [−2^31, 2^31 − 1]。请根据这个假设,如果反转后整数溢出那么就返回 0。
/** * 如果temp = rev⋅10 + pop 导致溢出,那么一定有rev ≥ INTMAX / 10 * 如果rev > INTMAX / 10,那么temp = rev⋅10 + pop 一定会溢出。 * 如果rev == INTMAX / 10,那么只要 pop > 7,temp = rev⋅10 + pop 就会溢出。 * 如果rev == INTMIN / 10,那么只要 pop <-8,temp = rev⋅10 + pop 就会溢出。 * Interger.MAX_VALUE = Math.pow(2,31)-1 = 2147483647 * Interger.MIN_VALUE = -Math.pow(2.31) = -2147483648 */ class Solution { public int reverse(int x) { int rev = 0; while(x != 0){ int pop = x % 10; x = x / 10; if(rev > Integer.MAX_VALUE / 10 || (rev == Integer.MAX_VALUE / 10 && pop > Integer.MAX_VALUE % 10)){ rev = 0; break; }else if(rev < Integer.MIN_VALUE / 10 || (rev == Integer.MIN_VALUE / 10 && x < Integer.MIN_VALUE % 10)){ rev = 0; break; } rev = rev * 10 + pop; } return rev; } }
LeetCode9.回文数
判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。
示例 1:
输入: 121
输出: true
示例 2:
输入: -121
输出: false
解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。
示例 3:
输入: 10
输出: false
解释: 从右向左读, 为 01 。因此它不是一个回文数。
进阶:
你能不将整数转为字符串来解决这个问题吗?
class Solution { public boolean isPalindrome(int x) { if(x<0 || (x%10==0 && x!=0)) return false ; //先排除小于0 或者 以0结尾且不为零的数 int result=0; while(x>result){ //判断一半长度即可 result = result*10 + x % 10; //反向取值 x /= 10; } return result==x || x==result/10; //前一半和后一半的反向值是否相等 或者 是否为 0< x <10 的数 } }
LeetCode13.罗马数字转整数
罗马数字包含以下七种字符: I, V, X, L,C,D 和 M。
字符 数值
I 1
V 5
X 10
L 50
C 100
D 500
M 1000
例如, 罗马数字 2 写做 II ,即为两个并列的 1。12 写做 XII ,即为 X + II 。 27 写做 XXVII, 即为 XX + V + II 。
通常情况下,罗马数字中小的数字在大的数字的右边。但也存在特例,例如 4 不写做 IIII,而是 IV。数字 1 在数字 5 的左边,所表示的数等于大数 5 减小数 1 得到的数值 4 。同样地,数字 9 表示为 IX。这个特殊的规则只适用于以下六种情况:
I 可以放在 V (5) 和 X (10) 的左边,来表示 4 和 9。
X 可以放在 L (50) 和 C (100) 的左边,来表示 40 和 90。
C 可以放在 D (500) 和 M (1000) 的左边,来表示 400 和 900。
给定一个罗马数字,将其转换成整数。输入确保在 1 到 3999 的范围内。
示例 1:
输入: “III”
输出: 3
示例 2:
输入: “IV”
输出: 4
示例 3:
输入: “MCMXCIV”
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.
import java.util.HashMap; import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner =new Scanner(System.in); String s =scanner.nextLine(); System.out.println(romanToInt(s)); } private static int romanToInt(String s) { HashMap<Character,Integer> hm = new HashMap<>(); hm.put('I',1); hm.put('V',5); hm.put('X',10); hm.put('L',50); hm.put('C',100); hm.put('D',500); hm.put('M',1000); int sum = 0; char ss[] = s.toCharArray(); for(int i =0;i < ss.length-1;i++){ if(hm.get(ss[i]) >= hm.get(ss[i+1])){ sum = sum + hm.get(ss[i]); }else { sum = sum + (hm.get(ss[i+1])- hm.get(ss[i])); i++; } } if(ss.length == 1){ return hm.get(ss[0]); } else if(hm.get(ss[ss.length-2]) >= hm.get(ss[ss.length-1])) return sum + hm.get(ss[ss.length-1]); else return sum; } }
LeetCode14.最长公共前缀
编写一个函数来查找字符串数组中的最长公共前缀。
如果不存在公共前缀,返回空字符串 “”。
示例 1:
输入: [“flower”,“flow”,“flight”]
输出: “fl”
示例 2:
输入: [“dog”,“racecar”,“car”]
输出: “”
解释: 输入不存在公共前缀。
说明:
所有输入只包含小写字母 a-z 。
//水平扫描法 每一个都和第一个字符串比较 class Solution { public String longestCommonPrefix(String[] strs) { if(strs == null || strs.length == 0) return ""; String prefix = strs[0]; for(int i = 1;i < strs.length;i++){ while(strs[i].indexOf(prefix) != 0){ prefix = prefix.substring(0, prefix.length()-1); if(prefix.isEmpty()) return ""; } } return prefix; } } //垂直扫描法 同时比较同一位置处字符是否相等 class Solution { public String longestCommonPrefix(String[] strs) { if(strs == null || strs.length == 0) return ""; for(int i = 0;i < strs[0].length();i++){ char c = strs[0].charAt(i); for(int j = 1;j < strs.length;j++){ if(i == strs[j].length() || strs[j].charAt(i) != c) return strs[0].substring(0,i); } } return strs[0]; } }
LeetCode20.有效的括号
给定一个只包括 ‘(’,’)’,’{’,’}’,’[’,’]’ 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入: “()”
输出: true
示例 2:
输入: “()[]{}”
输出: true
示例 3:
输入: “(]”
输出: false
示例 4:
输入: “([)]”
输出: false
示例 5:
输入: “{[]}”
输出: true
class Solution { public boolean isValid(String s) { char[] stack=new char[s.length()+1]; int top=1; for(char c:s.toCharArray()){ if(c=='('||c=='['||c=='{'){ stack[top++]=c; //左括号进栈,top+1,右括号出现就与前一位比较,相同就弹出前一位,top-1 }else if(c==')'&&stack[--top]!='('){ return false; }else if(c==']'&&stack[--top]!='['){ return false; }else if(c=='}'&&stack[--top]!='{'){ return false; } } return top==1; } }
LeetCode21.合并两个有序链表
将两个有序链表合并为一个新的有序链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。
示例:
输入:1->2->4, 1->3->4
输出:1->1->2->3->4->4
/** * Definition for singly-linked list. * public class ListNode { * int val; * ListNode next; * ListNode(int x) { val = x; } * } */ class Solution { public ListNode mergeTwoLists(ListNode l1, ListNode l2) { if(l1 == null) { return l2; } if(l2 == null) { return l1; } if(l1.val < l2.val) { l1.next = mergeTwoLists(l1.next, l2); //递归,判断下一个节点连接在哪里 return l1; //返回表头较小的链表 } else { l2.next = mergeTwoLists(l1, l2.next); return l2; } } }
LeetCode26.删除排序数组中的重复项
给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。
不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。
示例 1:
给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。
你不需要考虑数组中超出新长度后面的元素。
class Solution { public int removeDuplicates(int[] nums) { int j = 0; for(int i = 1; i < nums.length; i++){ if(nums[j] == nums[i]){ nums[i] = nums[i]; }else{ nums[j+1] = nums[i]; j++; } } return j+1; } }
LeetCode121. 买卖股票的最佳时机
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票),设计一个算法来计算你所能获取的最大利润。
注意你不能在买入股票前卖出股票。
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
示例 2:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
class Solution { public int maxProfit(int[] prices) { int len = prices.length; if (len < 2) { return 0; } // 有可能不做交易,因此结果集的初始值设置为 0 int res = 0; // 表示在当前位置之前的最小值,假设修正法(打擂台法) int minVal = prices[0]; // 注意:这里从 1 开始 for (int i = 1; i < len; i++) { res = Math.max(res, prices[i] - minVal); minVal = Math.min(minVal, prices[i]); } return res; } }
LeetCode122. 买卖股票的最佳时机II
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:
输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。
因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
解法一:谷峰法
解法二:连续爬坡
// 解法一: // 谷峰法 package cn.leetcode; import java.util.Scanner; public class leetcode122 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String p = sc.nextLine(); String p1[] = p.split(" "); int prices[] = new int[p1.length]; for (int i = 0; i < p1.length; i++){ prices[i] = Integer.parseInt(p1[i]); } System.out.println(maxProfit(prices)); } private static int maxProfit(int[] prices) { int i = 0; int valley = prices[0]; int peak = prices[0]; int maxprofit = 0; while (i < prices.length - 1) { while (i < prices.length - 1 && prices[i] >= prices[i + 1]) i++; valley = prices[i]; while (i < prices.length - 1 && prices[i] <= prices[i + 1]) i++; peak = prices[i]; maxprofit += peak - valley; } return maxprofit; } } // 解法二: // 将 谷峰法 变成 连续爬坡问题 // 谷峰法:找到最小值和最大值进行相减 // 连续爬坡:只要后面比前面大就相减,最后所有差值进行相加 // 时间复杂度:O(n),遍历一次。 // 空间复杂度:O(1),需要常量的空间。 class Solution { public int maxProfit(int[] prices) { int nums = 0; for(int i = 1; i < prices.length; i++){ if(prices[i] > prices[i-1]){ nums = nums + prices[i] - prices[i-1]; } } return nums; } }
LeetCode123. 买卖股票的最佳时机III
两次买入卖出
先看一个例子: 我手上有10元 第一次买入花了2元, 利润为 -2 元 第一次卖出,买了4元,利润为 4-2 = 2 元 第二次买入,花了3元,利润为 2-3 = -1 元 第二次卖出,卖了5元,利润为 -1 + 5 = 4 元 所以下面我们就定义了4个变量与上述4个过程对应: 第一次买入后的状态: minPrice1: 最低价格,要最小 第一次卖出后的状态: maxProfit1: 第一次交易最大利润,要最大 第二次买入后的状态: maxProfitAtferBuy: 第二次买入后的最大剩余利润,要最大 第二次卖出后的状态: maxProfit2: 当天能获得最大最大利润,要最大 即,算出第一次购买最低价,接着 买入就扣钱,卖出就加钱 除了第一次要比较购入最小值,其他参数更新都是和上次比较,取最大值保留 public int maxProfit(int[] prices) { int minPrice1 = Integer.MAX_VALUE; int maxProfit1 = 0; int maxProfitAfterBuy = Integer.MIN_VALUE; int maxProfit2 = 0; for(int price : prices) { // 1.第一次最小购买价格 minPrice1 = Math.min(minPrice1, price); // 2.第一次卖出的最大利润 maxProfit1 = Math.max(maxProfit1, price - minPrice1); // 3.第二次购买后的剩余净利润 maxProfitAfterBuy = Math.max(maxProfitAfterBuy, maxProfit1 - price ); // 4.第二次卖出后,总共获得的最大利润(第3步的净利润 + 第4步卖出的股票钱) maxProfit2 = Math.max(maxProfit2, price + maxProfitAfterBuy); } return maxProfit2; }
LeetCode371. 两数之和(位运算)
class Solution { public int getSum(int a, int b) { int c=0,d=0; while ((a&b)!=0){ //进位为0时结束 c=a^b; //c为进位,d为不进位求和 d=(a&b)<<1; a=c; b=d; } return a|b; //总值=进位值+不进位求和的值 } }
- LeetCode刷题笔记(Java版)----53、最大子序列和
- LeetCode笔记:94. Binary Tree Inorder Traversal
- LeetCode笔记--数组(3)
- leetCode 笔记 ————二叉树最小深度
- LeetCode笔记:508. Most Frequent Subtree Sum
- 27. Remove Element ---leetcode算法笔记
- leetcode笔记--Intersection of Two Linked Lists
- [leetCode刷题笔记]47. Permutations II
- leetcode笔记--Add Digits
- Leetcode第88题笔记
- LeetCode刷题笔记 495. 提莫攻击
- LeetCode笔记:223. Rectangle Area
- LeetCode笔记:462. Minimum Moves to Equal Array Elements II
- leetcode笔记:Best Time to Buy and Sell Stock II
- LeetCode刷题笔记(贪心):jump-game
- Leetcode解题笔记(Stack)
- leetcode笔记:Binary Tree Level Order Traversal II
- Leetcode刷题笔记 Top 100 Liked Questions和Top Interview Questions
- LeetCode笔记:263. Ugly Number
- leetcode的python实现 刷题笔记14:最长公共前缀