您的位置:首页 > 其它

bj_LeetCode刷题笔记

2020-06-05 08:01 120 查看

目录

  • LeetCode123. 买卖股票的最佳时机III
  • LeetCode371. 两数之和(位运算)
  • 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;  //总值=进位值+不进位求和的值
    }
    }
    内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
    标签: