Java 算法题笔记(九)

 买卖股票的最佳时机

给定一个数组,它的第 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。

暴力破解法,直接双重for 循环,依次拿第一个与后面的比较,类似于选择排序的写法。。

public int maxProfit(int prices[]){
        int maxprofit  = 0;
        for (int i=0; i<prices.length-1;i++){
            for (int j=i+1; j<prices.length;j++){
                int temp = prices[j] - prices[i];
                if (temp > maxprofit )
                    maxprofit  = temp;
            }
        }
        return maxprofit ;
    }

 上面的方法虽然简单,但是效率不是很高,毕竟两层循环,所以下面用一层循环解决一下。

针对[7, 1, 5, 3, 6, 4] 绘图有,

所以我们只需要用最小值记录最低点,之后遇到更小的就会更新最小值,遇到比最小值大的就计算差值,记录差值,但这个过程,如果晕倒更大的差值就更新差值。

public int maxProfit(int prices[]){
        int min = Integer.MAX_VALUE;
        int maxprofit  = 0;
        for (int i=0; i<prices.length;i++){
            if (prices[i] < min)
                min = prices[i];
            else if (prices[i] - min > maxprofit )
                maxprofit  = prices[i] - min;
        }
        return maxprofit ;
    }

买卖股票的最佳时机 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。

A + B > C ,将所有的峰值与低谷的差值都累加上,这样的利润最大。

public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0)
            return 0;
        int i = 0;
        int valley = prices[0];
        int peek = prices[0];
        int max = 0;
        while (i < prices.length-1){
            while (i < prices.length-1 && prices[i] >= prices[i+1]){
                i++;
            }
            volley = prices[i];
            while (i < prices.length-1 && prices[i] <= prices[i+1]){
                i++;
            }
            peek = prices[i];

            max += peek-volley;
        }
        return max;
    }

含有就是只要遇到上升的,即有利润就累加起来。

public int maxProfit(int[] prices) {
        int max = 0;
        for (int i=1; i<prices.length; i++){
            if (prices[i] > prices[i-1])
                max += prices[i] - prices[i-1];
        }
        return max;
    }

给定一个非负整数 num,反复将各个位上的数字相加,直到结果为一位数。

示例:

输入: 38  输出: 2 
解释: 各位相加的过程为:3 + 8 = 11, 1 + 1 = 2。 由于 2是一位数,所以返回 2。
public int addDigits(int num) {
        int sum = 0;
        while(num > 9){
            sum = 0;
            while(num > 0){
                int pop = num%10;
                sum += pop;
                num/=10;
            }
            num = sum;
        }
        
        return num;
    }
public int addDigits(int num) {
        if(num == 0)
            return 0;
        return num%9==0?9:num%9;
    }

编写一个函数,输入是一个无符号整数,返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)。

示例 1:

输入:00000000000000000000000000001011
输出:3
解释:输入的二进制串     00000000000000000000000000001011 中,共有三位为 '1'。
public int hammingWeight(int n) {
        int count = 0;
        while (n != 0){
            if ((n & 1) == 1){
                count++;
            }
            n=n >>> 1;
        }
        return count;
    }

>>> 无符号右移  参考:https://blog.csdn.net/qq_35402412/article/details/81156020

最长公共字串问题

这个算法的思想还是很重要的

class Solution {
    // 最长公共子串
    public String longestPalindrome(String s) {
        if (s.equals("")) {
            return "";
        }
        int length = s.length();
        String reversal = new StringBuffer(s).reverse().toString(); // 反转字符串
        int[][] cell = new int[length][length];
        int maxLen = 0; // 最长公共子串长度
        int maxEnd = 0; // 最长公共子串结束位置
        for (int i = 0; i < length; i++) {
            for (int j = 0; j < length; j++) {
                if (reversal.charAt(i) == s.charAt(j)) {
                    if (i == 0 || j == 0) {
                        cell[i][j] = 1;
                    } else {
                        cell[i][j] = cell[i - 1][j - 1] + 1; // 公共子串长度
                    }
                } else {
                    cell[i][j] = 0;
                }
                if (cell[i][j] > maxLen) {
                    maxLen = cell[i][j];
                    maxEnd = j;
                }
            }
        }
        return s.substring(maxEnd + 1 - maxLen, maxEnd + 1);
    }
}
  • 时间复杂度:O(n^2) -- 两层遍历。
  • 空间复杂度:O(n^2) -- 二维数组。

 

给定一个字符串 s,找到 s 中最长的回文子串。你可以假设 s 的最大长度为 1000。

输入: "babad"
输出: "bab"
注意: "aba" 也是一个有效答案。
输入: "cbbd"
输出: "bb"
    public boolean isPalindromic(String s) {
        int len = s.length();
        for (int i = 0; i < len / 2; i++) {
            // 一种对称写法可考虑当成公式写
            if (s.charAt(i) != s.charAt(len - i - 1)) {
                return false;
            }
        }
        return true;
    }

    // 暴力破解法
    public String longestPalindrome(String s) {
        String ans = "";
        int max = 0;
        int len = s.length();
        for (int i=0;i<len;i++){
            for (int j= i+1;j<=len;j++){
                String test = s.substring(i,j);
                if (isPalindromic(test) && test.length() > max){
                    ans = s.substring(i,j);
                    max = Math.max(max,ans.length());
                }
            }
        }
        return ans;
    }

可以看到3层for 循环, 时间复杂度为 O(n)  ,常数个,空间复杂度O(1)

 

public String longestPalindromzzze(String s) {
        if (s == null || s.length() < 1) return "";
        int start = 0, end = 0;
        for (int i = 0; i < s.length(); i++) {
            int len1 = expandAroundCenter(s, i, i);
            int len2 = expandAroundCenter(s, i, i + 1);
            int len = Math.max(len1, len2);
            if (len > end - start) {
                start = i - (len - 1) / 2;
                end = i + len / 2;
            }
        }
        return s.substring(start, end + 1);
    }

    // 2 - (4 - 1) / 2 由于i 可能站一位,-1 ) / 2
    // 3 - (5 - 1) / 2
    // 312214
    // 0    5
    // 5 - 0 - 1
    private int expandAroundCenter(String s, int left, int right) {
        int L = left, R = right;
        while (L >= 0 && R < s.length() && s.charAt(L) == s.charAt(R)) {
            L--;
            R++;
        }
        return R - L - 1;
    }

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值