Elementary Algorithm I

1. Remove duplicates in sorted array

Given an array nums arranged in ascending order, please delete the repeated elements in place so that each element appears only once, and return the new length of the array after deletion. The relative order of elements should remain consistent.

Since the length of an array cannot be changed in some languages, the result must be placed in the first part of the array nums. More formally, if there are k elements after removing duplicates, then the first k elements of nums should hold the final result.

Returns k after inserting the final result into the first k positions of nums.

Instead of using extra space, you must modify the input array in-place and do it using O(1) extra space.

Judgment criteria:

The system will use the following code to test your solution:

int[] nums = [...]; // 输入数组
int[] expectedNums = [...]; // 长度正确的期望答案

int k = removeDuplicates(nums); // 调用

assert k == expectedNums.length;
for (int i = 0; i < k; i++) {
    assert nums[i] == expectedNums[i];
}

If all assertions pass, your solution will be passed.

Example 1:

输入:nums = [1,1,2]
输出:2, nums = [1,2,_]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。

Example 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

hint:

1 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums 已按 升序 排列
Algorithm 1: (double pointer solution)

Using two pointers, the right pointer always moves to the right. If the value pointed by the right pointer is equal to the value pointed by the left pointer, the left pointer does not move. If the value pointed by the right pointer is not equal to the value pointed by the left pointer, then the left pointer moves one step to the right, and then assigns the value pointed by the right pointer to the left pointer.
Insert image description here
Insert image description here

class Solution {
    public int removeDuplicates(int[] nums) {
            //双指针解决
        //边界条件判断
        if ( nums == null ||  nums.length == 0)
            return 0;
        int left = 0;
        for (int right = 1; right < nums.length; right++)
            //如果左指针和右指针指向的值一样,说明有重复的,
            //这个时候,左指针不动,右指针继续往右移。如果他俩
            //指向的值不一样就把右指针指向的值往前挪
            if ( nums[left] !=  nums[right])
                 nums[++left] =  nums[right];
        return ++left;
    }
}
Algorithm 2: (Single pointer solution)
class Solution {
    public int removeDuplicates(int[] nums) {
         int count = 0;//重复的数字个数
        for (int right = 1; right <nums.length; right++) {
            if (nums[right] == nums[right - 1]) {
                //如果有重复的,count要加1
                count++;
            } else {
                //如果没有重复,后面的就往前挪
                nums[right - count] = nums[right];
            }
        }
        //数组的长度减去重复的个数
        return nums.length - count;
    }
}
Algorithm 3: (Simple algorithm to solve)

Loop: i=0, j=1, if the value of i is not equal to the value of j, then i moves backward one bit, and the value of j is assigned to i, and the final number is i+1

class Solution {
    public int removeDuplicates(int[] nums) {
          int i = 0;
          for (int j = 1; j < nums.length; j++) {
            if (nums[i] != nums[j]) {
                i++;
                nums[i] = nums[j];
            }
        }
        return i + 1;
    }
}

2. Best time to buy and sell stocks II

You are given an integer array prices, where prices[i] represents the price of a certain stock on day i. On each day, you can decide whether to buy and/or sell stocks. You can only hold a maximum of one share at any time. You can also buy first and then sell on the same day. Return the maximum profit you can make.

Example 1:

输入:prices = [7,1,5,3,6,4]
输出:7
解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。
随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。总利润为 4 + 3 = 7 。

Example 2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。总利润为 4 。

Example 3:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。

hint:

1 <= prices.length <= 3 * 104
0 <= prices[i] <= 104

idea:

The number in front is smaller than the number in the back

Loop, as long as the following number is greater than the previous one, use the following number - the previous number

Algorithm 1: (Dynamic programming solution)

Define dp[i][0] to represent the maximum profit without stocks in hand after the i-th day of trading, and dp[i][1] to represent the maximum profit from holding stocks after the i-th day of trading. There may be two situations if you don’t have stocks in hand after the day’s trading. One is that you didn’t make any transactions that day, and because you don’t have stocks in hand that day, the profit from no stocks that day can only be taken from the profit from the previous day that you didn’t have stocks in hand. One is to sell the stocks in hand on that day. Since it can be sold, it means that there are stocks in hand. Therefore, the profit of no stocks on that day is calculated by taking the profit of stocks in hand on the previous day plus the stock that can be sold on that day. price. In these two cases, we can just take the one with the largest profit, so we can get

dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);

There are two situations when you hold stocks in your hands after trading that day. One is that there are no transactions on that day, and because you hold stocks in your hands that day, the stocks you hold in your hands that day are actually already held the day before. Another way is to buy stocks on the same day. Being able to buy stocks on that day means that there must be no stocks in hand the day before. We take the maximum value of the two, so we can get

dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]);

Now that we have the recursive formula of dynamic programming, what are the boundary conditions? It’s the first day

If buying:

dp[0][1]=-prices[0];

If you didn’t buy it:

dp[0][0]=0;

but:

class Solution {
    public int maxProfit(int[] prices) {
     int max = 0;
        for (int i = 1; i < prices.length; i++) {
            if (prices[i] > prices[i - 1]) {
                max = max + (prices[i] - prices[i - 1]);
            }
        }
        return max;
    }
}
Algorithm 2: (code optimization)

In the above calculation, we see that the profit of the day is only related to the previous day. There is no need to use a two-dimensional array. We only need to use two variables, one records the maximum profit of the stock held after the transaction of the day, and the other records the transaction of the day. After finishing, there is no maximum profit from the stock in hand

class Solution {
 public int maxProfit(int[] prices) {
    if (prices == null || prices.length < 2)
        return 0;
    int length = prices.length;
    //初始条件
    int hold = -prices[0];//持有股票
    int noHold = 0;//没持有股票
    for (int i = 1; i < length; i++) {
        //递推公式转化的
        noHold = Math.max(noHold, hold + prices[i]);
        hold = Math.max(hold, noHold - prices[i]);
    }
    //最后一天肯定是手里没有股票的时候利润才会最大,
    //所以这里返回的是noHold
    return noHold;
}
}
Algorithm 3: (greedy algorithm solution)

If the stock keeps rising, you only need to find the maximum value when the stock rises and the minimum value when the stock starts to rise. Calculate the difference between them to be the maximum profit of the stock during this period. If the stock falls, there is no need to calculate. In the end, we only need to add up the profits of all stocks during the period of rising to get the result we require.

class Solution {
 public int maxProfit(int[] prices) {
    if (prices == null || prices.length < 2)
        return 0;
    int total = 0, index = 0, length = prices.length;
    while (index < length) {
        //如果股票下跌就一直找,直到找到股票开始上涨为止
        while (index < length - 1 && prices[index] >= prices[index + 1])
            index++;
        //股票上涨开始的值,也就是这段时间上涨的最小值
        int min = prices[index];
        //一直找到股票上涨的最大值为止
        while (index < length - 1 && prices[index] <= prices[index + 1])
            index++;
        //计算这段上涨时间的差值,然后累加
        total += prices[index++] - min;
    }
    return total;
}
}
Algorithm 4: (Greedy algorithm optimization)
class Solution {
   public int maxProfit(int[] prices) {
    int total = 0;
    for (int i = 0; i < prices.length - 1; i++) {
        //原数组中如果后一个减去前一个是正数,说明是上涨的,
        //我们就要累加,否则就不累加
        total += Math.max(prices[i + 1] - prices[i], 0);
    }
    return total;
}
}
Algorithm 5: (Simple algorithm solution)
class Solution {
    public int maxProfit(int[] prices) {
        if (prices.length == 0) {
            return 0;
        }

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

Guess you like

Origin blog.csdn.net/weixin_52733693/article/details/128508037