【LeetCode-面试经典150题-day3】

189. 轮转数组

题意:

给定一个整数数组 nums,将数组中的元素向右轮转 k 个位置,其中 k 是非负数。

【输入样例】

nums = [1,2,3,4,5,6,7],k=3

【输出样例】

[5,6,7,1,2,3,4]

解题思路1:

 直接暴力创建一个新的数组,通过寻找下标的转换规律将轮状后的数组存入临时数组,再将值赋给原数组,因为题目中没有要求返回值,判断的标准还是原数组的最终结果。注意:临时数组跟原数组的下标关系是nums1[i+k] = nums[i],这边需要判断是否超出nums.length-1

class Solution {
    public void rotate(int[] nums, int k) {
        //暴力解法,直接新建一个数组
        int[] nums1 = new int[nums.length];
        int j;
        for(int i = 0;i< nums.length;++i){
            j = i + k;
            if(j > nums.length-1) j %= nums.length;
            nums1[j] = nums[i];
        }

        for(int x=0;x<nums.length;x++){
            nums[x] = nums1[x];
        }
    }
}

时间: 击败了61.17%

内存: 击败了94.69%

解题思路2. 每次空出数组的最后一位,数组中所有程序往右边挪一个,但是这种情况当k比较大时,会出现超时的情况,仅供看看

class Solution {
    public void rotate(int[] nums, int k) {
        //每次空出数组的最后一位,进行挪值,这种情况会出现超时,时间复杂度是O(K*nums.length)
        int temp;//用来保留每一轮中数组的最后一位
        while(k>0){
            int endIndex = nums.length - 1;
            temp = nums[endIndex];
            while(endIndex>0){
                nums[endIndex] = nums[endIndex-1];
                --endIndex;
            }
            nums[0] = temp;
            --k;
        }
    }
}

 解题思路3. 环状替换解法

1.指针current指向当前要替换的数据,根据下标关系(参考解法1)找到目标位置(next),next指针指向的数据存储在临时变量temp中,之后将指针current指向的数据存储到next位置;

2. 修改current指针,指向next,循环执行1,指导current指针指向start;

3.此时证明出现环状,start指针向后挪一位,循环1,2;

4.循环过程中定义一个count变量,统计已经有多少个数据交换过。

class Solution {
    public void rotate(int[] nums, int k) {
        //环状替换
        int count = 0;
        int current = 0;
        int start = 0;
        int length =  nums.length;
        while(count <length){
            current = start;
            int prev = nums[start];
            do{
                int next = (current + k) % length;
                int temp = nums[next];
                nums[next] = prev;
                prev = temp;
                current = next;
                ++count;
            }while(current != start);
            ++start;
        }
    }
}

时间: 击败了61.17%

内存: 击败了48.46%(哦吼,还不如新建一个数组哈哈哈)

 121.买卖股票的最佳时机

题意:

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

【输入样例】

[7,1,5,3,6,4]

【输出样例】

5

解题思路1:直接暴力枚举,然后不出意外的超时了~

class Solution {
    public int maxProfit(int[] prices) {
        //直接暴力枚举,会超时哈哈哈哈哈!!!!
        int maxPro = 0;
        int buy;
        int proTemp;
        for(int i=0;i<prices.length-1;++i){
            buy = prices[i];
            for(int j=i+1;j<prices.length;++j){
                proTemp = prices[j] - buy;
                if(proTemp >0 && proTemp > maxPro){
                    maxPro = proTemp;
                }
            }
        }
        return maxPro;
    }
}

 解题思路2:动态规划~

1.设置一个变量minPri,存储前i天中的历史局部最小价格

2. 定义一个变量maxPri,存储能获得的最大利润

3. 假设第i天卖出股票,那其购买时间肯定在[0,i-1]天中,因此,计算price[i]与minPri之间的差值,如果大于maxPri,重新赋值maxPri,否则继续往下寻找更合适的卖出时间

class Solution {
    public int maxProfit(int[] prices) {
        //动态规划
        int maxPri = 0;
        int minPri = Integer.MAX_VALUE;
        for(int i=0;i<prices.length;++i){
            if(prices[i] < minPri){
                minPri = prices[i];
            }else if(prices[i] - minPri > maxPri){
                maxPri = prices[i] - minPri;
            }
        }
        return maxPri;
    }
}

时间: 击败了100.00%

内存: 击败了38.73%

 122.买卖股票的最佳时机II

题意:

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。

【输入样例】

[7,1,5,3,6,4]

【输出样例】

7

1买入,5卖出,收入4;3买入,6卖出;收入3

解题思路1:贪心一下,有利润就出售

class Solution {
    public int maxProfit(int[] prices) {
        //贪心一下
        int maxPro = 0;
        int len = prices.length;
        for(int i=1;i<len;++i){
            maxPro += Math.max(0,prices[i] - prices[i-1]);
        }
        return maxPro;
    }
}

时间: 击败了72.35%

内存: 击败了43.65%

解题思路2:动态规划(参考官方,我太菜了)

1.矩阵dp[i][0]表示第i天交易后手里没有股票的最大利润,dp[i][1]表示第i天交易后手机还有一只股票的最大利润;

2.dp[i][0]的可能是前一天就没有股票dp[i-1][0],也可能是前一天有股票,然后今天卖出dp[i-1][1]+prices[i];为了收益最大化,去最值;

3.dp[i][1]可能是前一天手上就有一只股票了dp[i-1][1],也可能是前一天还没有股票,今天刚买入dp[i-1][0]-prices[i],减是因为需要花钱购买。

class Solution {
    public int maxProfit(int[] prices) {
        //贪心一下
        int len = prices.length;
        int[][] dp = new int[len][2];
        dp[0][0] = 0;//今天没有股票
        dp[0][1] = -prices[0];//今天买了一直股票,需要支出prices[0]
        //虽然不计算亏损多少钱,但是这里dp[0][1]需要存储买了股票的价格是为了后面计算,第i天卖出能获得的最大利润究竟是0(亏损或者没收入)还是有收入
        for(int i=1;i<= len-1;++i){
            dp[i][0] = Math.max(dp[i-1][0],dp[i-1][1]+prices[i]);
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]-prices[i]);
        }
        return dp[len-1][0];//最后一天手上肯定是没有股票了
    }
}

时间: 击败了29.18%

内存: 击败了65.59% 

 55.跳跃游戏

题意:

给你一个非负整数数组 nums ,你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。

判断你是否能够到达最后一个下标,如果可以,返回 true ;否则,返回 false 。

【输入样例】

[2,3,1,1,4]

【输出样例】

true

解题思路1:递归,反向扫描数组,找到第一个能一步跳到数组末尾的下标

class Solution {
    public boolean canJump(int[] nums) {
        if(nums == null || nums.length == 0){
            return true;
        }
        return findJump(nums,nums.length-1);
    }

    boolean findJump(int nums[],int end){
        if(end == 0){
            //当跳到下标为0时,表示一条路径被找到
            return true;
        }
        int current = 0;//反向扫描数组,找到第一个能一步跳到数组末尾的下标
        for(int i=end -1;i>=0;--i){
            if(i + nums[i] >= end){
                //yeah,找到啦,我去找正向扫描数组,找到第一个能一步跳到i的下标啦
                current = i;
                return findJump(nums,current);
            }
        }
        return false;
    }
}

时间: 击败了22.10%

内存: 击败了39.84% 

 解题思路2:贪心算法,感觉思路与递归类似,正向遍历数组中的每一个位置,并实时维护最远可以到达的位置,在遍历的过程中,如果最远可以到达的位置大于等于数组中的最后一个位置,那说明可到达,返回true;若是遍历结束后最后一个位置仍不可到达,则返回false。

class Solution {
    public boolean canJump(int[] nums) {
        if(nums == null || nums.length == 0){
            return true;
        }
       int len = nums.length;
       int maxRight = 0;
       for(int i=0;i<len;++i){
           if(i <= maxRight){
               maxRight = Math.max(maxRight, i + nums[i]);
               if(maxRight >= len - 1){
                   return true;
               }
           }
       }
       return false;
    }

}

时间: 击败了91.57%

内存: 击败了6.11%  

45.跳跃游戏II

题意:

给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]

每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。换句话说,如果你在 nums[i] 处,你可以跳转到任意 nums[i + j] 处:

  • 0 <= j <= nums[i] 
  • i + j < n

返回到达 nums[n - 1] 的最小跳跃次数。生成的测试用例可以到达 nums[n - 1]

【输入样例】

[2,3,1,1,4]

【输出样例】

2

解题思路:生成的测试用例一定能到达nums[n-1],所以不存在不能到达的问题,由于要寻找最小跳跃次数,所以每次贪心一点,步子迈最大。

class Solution {
    public int jump(int[] nums) {
        //贪心点好啊
        int len = nums.length;
        int end = 0;
        int maxPosition = 0;//当前能到达的最大下标是哪一个
        int count = 0;
        for(int i = 0; i < len - 1; ++i){
            maxPosition = Math.max(maxPosition,i+nums[i]);
            if(i == end){
                end = maxPosition;
                ++count;
            }
        }
        return count;
    }
}

时间: 击败了98.79%

内存: 击败了39.59%  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值