题目大意
给定一个数组 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])
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数组中从头开始遍历,找到开始上涨的最小值,然后这一上涨阶段的最大值,最小值买入,最大值卖出,就能获得最大利润
public int maxProfit(int[] prices) {
int len = prices.length;
int ans=0;
for (int i=1;i
题目大意
给定一个数组,将数组中的元素向右移动 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个元素整体将会交换位置,可以先将整体交换,即直接反转元素,然后在每个部分中再反转即可。
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;
}
}
题目大意
给定一个整数数组,判断是否存在重复元素。
如果存在一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。
示例 1
输入: [1,2,3,1]
输出: true
解题思路—set
直接暴力求解的话效率非常低,可以使用set的add方法一个特性:当添加的对象在set中已经存在,会add失败返回false。
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
题目大意
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
解题思路—异或
利用位运算符异或,相同的数字异或为0,然后任何数与0异或为本身,所以直接将所有数字进行异或即可
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只剩下一个不重复的元素,这个的效率不如上一种方法
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];
}
题目大意
给定一个字符串,找到它的第一个不重复的字符,并返回它的索引。如果不存在,则返回 -1。
示例:
s = "leetcode"
返回 0
s = "loveleetcode"
返回 2
解题思路
关于字符串的问题要善于运用一个一维数组a[26],来记录每一个字符的出现次数。遍历给定字符串的每一个字符,出现一次便在数组中加一,最后按顺序遍历找出值为一的元素索引返回,不存在即返回-1。
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;
}
题目大意
编写一个函数来查找字符串数组中的最长公共前缀。如果不存在公共前缀,返回空字符串 ""。
示例 1:
输入:strs = ["flower","flow","flight"]
输出:"fl"
示例 2:
输入:strs = ["dog","racecar","car"]
输出:""
解题思路
一种简单的思路就是暴力从0开始枚举所有字符串判断,但效率较低,一种优化的解法则是利用IndexOf函数来判断,不断截取公共字符串
public String longestCommonPrefix(String[] strs) {
if (strs == null || strs.length == 0)
return "";
String pre = strs[0];
if(strs.leng == 1) return pre;
int i = 1;
while (i < strs.length) {
while (strs[i].indexOf(pre) != 0)
pre = pre.substring(0, pre.length() - 1);
i++;
}
return pre;
}
题目大意
给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。
有效 二叉搜索树定义如下:
节点的左子树只包含 小于 当前节点的数。
节点的右子树只包含 大于 当前节点的数。
所有左子树和右子树自身必须也是二叉搜索树。
解题思路
我最初写的错误的解法如下,因为只考虑到局部是否符合,而没考虑到全局
public boolean isValidBST(TreeNode root) {
if(root == null) return true;
if(root.left!=null&&root.left.val>root.val
|| root.right!=null&&root.right.val<root.val) return false;
return isValidBST(root.left) && isValidBST(root.right);
}
正确的解题如下:
public boolean isValidBST(TreeNode root) {
return isValidBST(root,Long.MIN_VALUE, Long.MAX_VALUE);
}
public boolean isValidBST(TreeNode root, long min , long max){
if(root ==null) return true;
if(root.val<=min || root.val>=max) return false;
return isValidBST(root.left, min, root.val) && isValidBST(root.right, root.val, max);
}
题目大意
给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。
示例:
二叉树:[3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
返回其层序遍历结果:
[
[3],
[9,20],
[15,7]
]
解题思路
关于二叉树的层次遍历应该是比较基础的,即利用队列实现即可,但是这道题要求划分每一个层次来输出二叉树的节点值,就要用到一点小技巧了,如下所示
public List<List<Integer>> levelOrder(TreeNode root) {
Queue<TreeNode> queue = new LinkedList<>();
if(root==null) return new ArrayList<>();
queue.add(root);
List<List<Integer>> list = new ArrayList<>();
while (!queue.isEmpty()){
//利用size来划分层次
int size = queue.size();
List<Integer> sublist = new ArrayList<>();
for(int i=0;i<size;i++) {
TreeNode node = queue.poll();
if(node.left!=null) queue.add(node.left);
if(node.right!=null) queue.add(node.right);
sublist.add(node.val);
}
list.add(sublist);
}
return list;
}