LeetCode刷题日记——初级算法 1.买卖股票的最佳时机
题目大意
1 2 3 4 5 6 7 8 给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。 设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。 注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。 示例: 输入: prices = [7,1,5,3,6,4] 输出: 7 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
动态规划解题
建立一个二维数组,dp[i][0]
代表第i天手中没有股票时的现有利润,dp[i][1]
代表第i天手中有股票时的最大利润,则递推公式如下:dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i])
,dp[i][1]=max(dp[i-1][0]-prices[i],dp[i-1][1])
1 2 3 4 5 6 7 8 9 10 11 public int maxProfit (int [] prices) { int len = prices.length; int [][] dp = new int [len][2 ]; dp[0 ][0 ]=0 ; dp[0 ][1 ]=-prices[0 ]; for (int i=1 ;i<len;i++){ dp[i][0 ] = Math.max(dp[i-1 ][0 ],dp[i-1 ][1 ]+prices[i]); dp[i][1 ] = Math.max(dp[i-1 ][0 ]-prices[i],dp[i-1 ][1 ]); } return dp[len-1 ][0 ]; }
贪心算法解题
贪心算法,即局部最优,只需要在prices数组中从头开始遍历,找到开始上涨的最小值,然后这一上涨阶段的最大值,最小值买入,最大值卖出,就能获得最大利润
1 2 3 4 5 6 7 8 public int maxProfit (int [] prices) { int len = prices.length; int ans=0 ; for (int i=1 ;i<len;i++){ ans += Math.max(0 ,prices[i]-prices[i-1 ]); } return ans; }
2.旋转数组
题目大意
1 2 3 4 5 6 7 8 9 给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。 示例: 输入: nums = [1,2,3,4,5,6,7], k = 3 输出: [5,6,7,1,2,3,4] 解释: 向右旋转 1 步: [7,1,2,3,4,5,6] 向右旋转 2 步: [6,7,1,2,3,4,5] 向右旋转 3 步: [5,6,7,1,2,3,4]
题解
以题目示例来说,旋转之后,左边的4个元素整体和右边的3个元素整体将会交换位置,可以先将整体交换,即直接反转元素,然后在每个部分中再反转即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public void rotate (int [] nums, int k) { int len = nums.length; k %= len; reverse(nums,0 ,len-1 ); reverse(nums,0 ,k-1 ); reverse(nums,k,len-1 ); for (int num : nums) { System.out.println(num); } } public void reverse (int [] nums,int start, int end) { while (start<end){ int temp = nums[start]; nums[start++]=nums[end]; nums[end--]=temp; } }
3.存在重复元素
题目大意
1 2 3 4 5 6 给定一个整数数组,判断是否存在重复元素。 如果存在一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。 示例 1 输入: [1,2,3,1] 输出: true
解题思路—set
直接暴力求解的话效率非常低,可以使用set的add方法一个特性:当添加的对象在set中已经存在,会add失败返回false。
1 2 3 4 5 6 7 public boolean containsDuplicate (int [] nums) { Set<Integer> set = new HashSet<>(); for (int i : nums){ if (!set.add(i)) return true ; } return false ; }
解题思路—排序后比较
可以使用java内置的排序函数,先进行排序,在用O(n)的时间复杂度进行比较,最后的时间复杂度为排序的时间复杂度nlogn,使用leetcode发现这一种方法所使用的时间和空间要优于使用set
4.只出现一次的数字
题目大意
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
解题思路—异或
利用位运算符异或,相同的数字异或为0,然后任何数与0异或为本身,所以直接将所有数字进行异或即可
1 2 3 4 5 6 7 public int singleNumber (int [] nums) { int ans=0 ; for (int i=0 ;i<nums.length;i++){ ans=ans^nums[i]; } return ans; }
解题思路—set
使用set的add特性,当添加失败时说明其为重复元素,直接将它移除,最后set只剩下一个不重复的元素,这个的效率不如上一种方法
1 2 3 4 5 6 7 8 9 public int singleNumber (int [] nums) { Set<Integer> set = new HashSet<>(); for (int i=0 ;i<nums.length;i++){ if (!set.add(nums[i])){ set.remove(nums[i]); } } return (int )set.toArray()[0 ]; }
5.字符串中的第一个唯一字符
题目大意
1 2 3 4 5 6 7 8 给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。 示例: s = "leetcode" 返回 0 s = "loveleetcode" 返回 2
解题思路
关于字符串的问题要善于运用一个一维数组a[26],来记录每一个字符的出现次数。遍历给定字符串的每一个字符,出现一次便在数组中加一,最后按顺序遍历找出值为一的元素索引返回,不存在即返回-1。
1 2 3 4 5 6 7 8 9 10 public static int firstUniqChar (String s) { int a[] = new int [26 ]; for (int i=0 ;i<s.length();i++){ a[s.charAt(i)-'a' ]++; } for (int i=0 ;i<s.length();i++){ if (a[s.charAt(i)-'a' ]==1 ) return i; } return -1 ; }