目录
1.best-time-to-buy-and-sell-stock
2.best-time-to-buy-and-sell-stock-ii
3.best-time-to-buy-and-sell-stock-iii
4.first-missing-positive
5.remove-duplicates-from-sorted-array
6.remove-duplicates-from-sorted-array-ii
7.merge-sorted-array
8.convert-sorted-array-to-binary-search-tree
9.two-sum
10.3sum
11.3sum-closest
12.4sum
题目:假设你有一个数组,其中第i个元素是某只股票在第i天的价格。如果你最多只能完成一笔交易(即买一股和卖一股股票),设计一个算法来求最大利润。
分析:见剑指offer面试题63 https://blog.csdn.net/Nibaby9/article/details/104126765
题目:假设你有一个数组,其中第i个元素表示某只股票在第i天的价格。设计一个算法来寻找最大的利润。你可以完成任意数量 的交易(例如,多次购买和出售股票的一股)。但是,你不能同时进行多个交易(即,你必须在再次购买之前卖出之前买的股票)。
分析:贪心法,相邻两天的股票价格只要是递增,利润就会加大。
public int maxProfit(int[] prices) {
if(prices == null || prices.length == 0)
return 0;
int max_profit = 0;
for(int i = 1;i < prices.length;i++){
if(prices[i] - prices[i-1] > 0)
max_profit += prices[i] - prices[i-1];
}
return max_profit;
}
题目:假设你有一个数组,其中第i个元素是某只股票在第i天的价格。设计一个算法来求最大的利润。你最多可以进行两次交易。注意:你不能同时进行多个交易(即,你必须在再次购买之前出售之前买的股票)。
分析:贪心法。无论是买还是卖,模拟两次买和卖,都取利润的最大值即可。
public int maxProfit(int[] prices) {
if(prices == null || prices.length == 0)
return 0;
int buy1 = Integer.MIN_VALUE,sell1 = 0,buy2 = Integer.MIN_VALUE,sell2 = 0;
for(int i = 0;i < prices.length;i++){
buy1 = Math.max(buy1,-prices[i]);//第一次买股票的利润
sell1 = Math.max(sell1,prices[i] + buy1);//第一次卖股票后所盈利的
buy2 = Math.max(buy2,sell1 - prices[i]);//第二次买股票后的利润:第一次的利润 - 股票钱
sell2 = Math.max(sell2,prices[i] + buy2);
}
return sell2;
}
题目:给出一个无序的整数型数组,求不在给定数组里的最小的正整数。例如:给出的数组为[1,2,0] 返回3,给出的数组为[3,4,-1,1] 返回2.你需要给出时间复杂度在O(n)之内并且空间复杂度为常数级的算法。
分析:数组下标从0开始,让数组中满足大于0和小于数组长度的数都满足a[i]==i+1(注意:不能直接用A[i] != i+1来作为循环条件,因为有可能数组中根本i+1这个数),最后再遍历数组第一个不满足a[i]==i+1的就是缺失的最小正整数。
public int firstMissingPositive(int[] A) {
for(int i = 0;i < A.length;i++){
while(A[i] > 0 && A[i] <= A.length && A[i] != A[A[i]-1]){
int temp = A[A[i]-1];A[A[i]-1] = A[i];A[i] = temp;//swap(A[i],A[A[i]-1]);
}
}
for(int i = 0;i < A.length;i++){
if(A[i] != i+1)
return i+1;
}
return A.length + 1;
}
题目:给定一个已排序的数组,使用就地算法将重复的数字移除,使数组中的每个元素只出现一次,返回新数组的长度。不能为数组分配额外的空间,你必须使用常熟级空间复杂度的就地算法。例如,给定输入数组 A=[1,1,2],你给出的函数应该返回length=2,A数组现在是[1,2]。
分析:用len来标记数组当前加入非重复数字的有效长度即可。
public int removeDuplicates(int[] A) {
if(A.length == 0)
return 0;
int len = 0;
for(int i = 1;i < A.length;i++){
if(A[i] != A[i-1])
A[++len] = A[i];
}
return len+1;
}
题目:继续思考题目"Remove Duplicates":如果数组中元素最多允许重复两次呢?例如:给出有序数组 A =[1,1,1,2,2,3],你给出的函数应该返回length =5, A 变为[1,1,2,2,3].
分析:在上题的基础上,多加一个flag来标志某元素重复的次数即可。
public int removeDuplicates(int[] A) {
if(A == null || A.length == 0)
return 0;
int len = 1,flag = 1;
for(int i = 1;i < A.length;i++){
if(A[i] != A[i-1]){
A[len++] = A[i];
flag = 1;
}
else if(flag == 1){
flag++;
A[len++] = A[i];
}
}
return len;
}
题目:给出两个有序的整数数组A和B,请将数组B合并到数组A中,变成一个有序的数组。注意:可以假设A数组有足够的空间存放B数组的元素,A和B中初始的元素数目分别为m和n
分析:将数从后往前依次放入即可。
public void merge(int A[], int m, int B[], int n) {
int i = m-1,j = n-1,x = m + n -1;
while(i >= 0 && j >= 0){
if(A[i] > B[j])
A[x] = A[i--];
else
A[x] = B[j--];
x--;
}
while(j >= 0)
A[x--] = B[j--];
}
题目:给出一个升序排序的数组,将其转化为平衡二叉搜索树(BST).
分析:找中间结点mid = (left + right)/2作为根结点,递归求出左右子树即可。出口易错!!!
public TreeNode sortedArrayToBST(int[] num) {
if(num == null || num.length == 0)
return null;
return toBST(num,0,num.length);
}
private TreeNode toBST(int[] num, int left, int right) {
if(left >= right ) //易错
return null;
int mid = (left + right) / 2;
TreeNode root = new TreeNode(num[mid]);
root.left = toBST(num,left,mid);
root.right = toBST(num,mid+1,right);
return root;
}
题目:给出一个整数数组,请在数组中找出两个加起来等于目标值的数,你给出的函数twoSum 需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2.。注意:下标是从1开始的,假设给出的数组中只存在唯一解。例如:给出的数组为 {2, 7, 11, 15},目标值为9,输出 ndex1=1, index2=2。
分析:用HashMap来存储每个数字的下标即可。
若数组已排好序,参见剑指offer面试题57 https://blog.csdn.net/Nibaby9/article/details/104126811
public int[] twoSum(int[] numbers, int target) {
int [] re = new int[2];
HashMap map = new HashMap<>();
for(int i = 0;i < numbers.length;i++){
if(map.containsKey(target - numbers[i])){
re[0] = map.get(target - numbers[i]);
re[1] = i + 1;
return re;
}
else{
map.put(numbers[i],i+1);
}
}
return re;
}
题目:给出一个有n个元素的数组S,S中是否有元素a,b,c满足a+b+c=0?找出数组S中所有满足条件的三元组。注意:三元组(a、b、c)中的元素必须按非降序排列。(即a≤b≤c);解集中不能包含重复的三元组。 例如,给定的数组 S = {-1 0 1 2 -1 -4},↵↵ 解集为:↵ (-1, 0, 1)↵ (-1, -1, 2)
分析:先对数组排好序,然后固定第一个数字,就可以将问题转化为查找两个数为目标值。但是需特别注意去重问题!!!
public ArrayList> threeSum(int[] num) {
ArrayList> res = new ArrayList<>();
if(num.length < 3)
return res;
Arrays.sort(num);
for(int i = 0;i < num.length - 2;i++){
if(num[i] + num[i+1] + num[i+2] > 0)
return res;
if(i > 0 && num[i] == num[i-1])
continue;
if(num[i] + num[num.length - 1] + num[num.length - 2] < 0)
continue;
int low = i + 1;
int high = num.length - 1;
while(low < high){
if(num[i] + num[low] + num[high] == 0){
ArrayList list = new ArrayList<>();
list.add(num[i]);list.add(num[low]);list.add(num[high]);
res.add(list);
low++;high--;
while(low < high && num[low] == num[low-1])
low++;
while(low < high && num[high] == num[high+1])
high--;
}
else if(num[i] + num[low] + num[high] > 0)
high--;
else
low++;
}
}
return res;
}
题目:给出含有n个整数的数组s,找出s中和加起来的和最接近给定的目标值的三个整数。返回这三个整数的和。你可以假设每个输入都只有唯一解。 例如,给定的整数 S = {-1 2 1 -4}, 目标值 = 1.↵↵ 最接近目标值的和为 2. (-1 + 2 + 1 = 2).
分析:跟上题思想一样,只是在计算的过程中需记录离目标值最接近的值。
public int threeSumClosest(int[] num, int target){
if(num.length < 3)
return 0;
Arrays.sort(num);
int res = num[0] + num[1] + num[2];
for(int i = 0;i < num.length - 2;i++){
if(i > 0 && num[i] == num[i-1])
continue;
int low = i + 1;
int high = num.length - 1;
while(low < high){
int sum = num[i] + num[low] + num[high];
if(sum == target)
return target;
else if(sum > target)
high--;
else
low++;
if(Math.abs(target - sum) < Math.abs(target - res))
res = sum;
}
}
return res;
}
题目:给出一个有n个元素的数组S,S中是否有元素a,b,c和d满足a+b+c+d=目标值?找出数组S中所有满足条件的四元组。注意:四元组(a、b、c、d)中的元素必须按非降序排列。(即a≤b≤c≤d);解集中不能包含重复的四元组。 例如:给出的数组 S = {1 0 -1 0 -2 2}, 目标值 = 0.↵↵ 给出的解集应该是:↵ (-1, 0, 0, 1)↵ (-2, -1, 1, 2)↵ (-2, 0, 0, 2)
分析:固定一个数,就可把问题转换为满足目标值得三元组。
public ArrayList> fourSum(int[] num, int target) {
ArrayList> res = new ArrayList<>();
if(num.length < 4)
return res;
Arrays.sort(num);
for(int i = 0;i < num.length - 3;i++){
if(num[i] + num[i+1] + num[i+2] + num[i+3] > target)
return res;
if(i > 0 && num[i] == num[i-1])
continue;
if(num[i] + num[num.length - 1] + num[num.length - 2] + num[num.length - 3] < target)
continue;
for(int j = i + 1;j < num.length - 2;j++){
if(num[i] + num[j] + num[j+1] + num[j+2] > target)
break;
if(j > i + 1 && num[j] == num[j-1])
continue;
if(num[i] + num[j] + num[num.length - 1] + num[num.length - 2] < target)
continue;
int low = j + 1;
int high = num.length - 1;
while(low < high){
if(num[i] + num[j] + num[low] + num[high] == target){
ArrayList list = new ArrayList<>();
list.add(num[i]);list.add(num[j]);list.add(num[low]);list.add(num[high]);
res.add(list);
low++;high--;
while(low < high && num[low] == num[low-1])
low++;
while(low < high && num[high] == num[high+1])
high--;
}
else if(num[i] + num[j] + num[low] + num[high] > target)
high--;
else
low++;
}
}
}
return res;
}