1.买卖股票的最佳时机II
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
解题思路:
如果后一天的股票值大于前一天,就把股票卖掉,累计利润就是最大利润。
class Solution {
public int maxProfit(int[] prices) {
int maxprofit = 0;
for(int i = 1;i<prices.length;i++){
if(prices[i] > prices[i-1]){
maxprofit += prices[i] - prices[i-1];
}
}
return maxprofit;
}
}
运行结果:
2.两数之和II
给定一个已按照升序排列 的有序数组,找到两个数使得它们相加之和等于目标数。
函数应该返回这两个下标值 index1 和 index2,其中 index1 必须小于 index2。
说明:
返回的下标值(index1 和 index2)不是从零开始的。
你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。
解题思路:
设置两个指针p1和p2,分别指向数组的头和尾,当头加尾的值大于目标值,则p2–;当头加尾的值小于目标值,则p1++;如果恰好等于目标值,则返回头尾指针加1的值,因为下标值是从1开始的。
class Solution {
public int[] twoSum(int[] numbers, int target) {
int low = 0;
int high = numbers.length-1;
int[] nums = new int[2];
while(low < high){
if(numbers[low] + numbers[high] > target){
high--;
}else if(numbers[low] + numbers[high] < target){
low++;
}else{
nums[0] = low+1;
nums[1] = high+1;
break;
}
}
return nums;
}
}
运行结果:
3.多数元素
给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数大于 ⌊ n/2 ⌋ 的元素。
你可以假设数组是非空的,并且给定的数组总是存在多数元素。
解题思路:
维护一个候选众数 result和它出现的次数 count。初始时 result设为nums[0],count 为 1;遍历数组 nums 中的所有元素,对于每个元素 x,在判断 x 之前,如果 count 的值为 0,我们先将 x 的值赋予 result,随后我们判断 x:如果 x 与 result相等,那么计数器 count 的值增加 1;如果 x 与 result不等,那么计数器 count 的值减少 1。在遍历完成后,result即为整个数组的众数。将count重新设置为0,遍历数组,计算result的出现次数,如果出现次数乘2大于数组长度,那么就返回result,否则返回0。
class Solution {
public int majorityElement(int[] nums) {
int count = 1;
int len = nums.length;
int result = nums[0];
for(int i = 1;i < len;i++){
if(count == 0){
result = nums[i];
count++;
}else{
if(nums[i] == result){
count++;
}else{
count--;
}
}
}
count = 0;
for(int i = 0;i < len;i++){
if(result == nums[i]){
count++;
}
}
if(count * 2 <= len){
result = 0;
}
return result;
}
}
运行结果:
4.旋转数组
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。
解题思路:
借助一个新的数组。
class Solution {
public void rotate(int[] nums, int k) {
int[] a = new int[nums.length];
for (int i = 0; i < nums.length; i++) {
a[(i + k) % nums.length] = nums[i];
}
for (int i = 0; i < nums.length; i++) {
nums[i] = a[i];
}
}
}
运行结果:
5.存在重复元素
给定一个整数数组,判断是否存在重复元素。
如果任意一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。
解题思路:
用map保存数组中的值和它的次数,遍历数组,如果map中已经包含了某个值,返回true,结束遍历;否则将该值和其出现次数加入map。
import java.util.*;
class Solution {
public boolean containsDuplicate(int[] nums) {
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
boolean result = false;
for(int i = 0;i < nums.length;i++){
if(map.containsKey(nums[i])){
result = true;
break;
}else{
map.put(nums[i], 1);
}
}
return result;
}
}
运行结果:
6.存在重复元素II
给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。
解题思路:
用map保存数组中的值和它的索引,遍历数组,如果map中已经包含了某个值,判断两者的索引差的绝对值是否大于k,如果大于k,将该值和现在的索引重新放入map中。
import java.util.HashMap;
import java.util.Map;
class Solution {
public boolean containsNearbyDuplicate(int[] nums, int k) {
Map<Integer,Integer> map = new HashMap<Integer,Integer>();
boolean result = false;
for(int i = 0;i < nums.length;i++){
if(map.containsKey(nums[i])){
if(Math.abs(map.get(nums[i]) - i ) <= k){
result = true;
break;
}else{
map.put(nums[i], i);
}
}else{
map.put(nums[i], i);
}
}
return result;
}
}
运行结果:
7.缺失数字
给定一个包含 0, 1, 2, …, n 中 n 个数的序列,找出 0 … n 中没有出现在序列中的那个数。 解题思路:
思路1:
先将数组进行排序。判断数组第一个数组是否为0 ,不为0,缺失的数字为0;判断数组最后一个数字是否为n,不为n,则缺失的数字为n。第三种情况判断任意中间两个相邻数的差是否大于1,若大于1,则返回前一个数+1的值或者后一个数减1的值。
class Solution {
public static int missingNumber(int[] nums) {
int result = 0;
Arrays.sort(nums);
if(nums[nums.length-1] != nums.length){
result = nums.length;
}
if(nums[0] != 0){
result = 0;
}
for(int i = 0;i < nums.length-1;i++){
if(nums[i+1]-nums[i]>1){
result = nums[i] + 1;
}
}
return result;
}
}
运行结果:
思路2:用高斯求和公式求出0到n的和,然后减去数组的和,就是缺失的数字。
class Solution {
public static int missingNumber(int[] nums) {
int sum = nums.length * (nums.length+1) / 2;
int actSum = 0;
for(int num:nums){
actSum += num;
}
int result = sum-actSum;
return result;
}
}
运行结果:
8.移动零
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
说明:
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。
解题思路:
用0当做中间点,把不等于0的放到中间点的左边,等于0的放到其右边。我们使用两个指针i和p1,只要nums[i]!=0,我们就交换nums[i]和nums[p1]。
class Solution {
public void moveZeroes(int[] nums) {
int p1 = 0;
for(int i = 0;i < nums.length;i++){
if(nums[i] != 0){
int temp = nums[i];
nums[i] = nums[p1];
nums[p1++] = temp;
}
}
}
}
运行结果:
9.第三大的数
给定一个非空数组,返回此数组中第三大的数。如果不存在,则返回数组中最大的数。要求算法时间复杂度必须是O(n)。
解题思路:
利用TreeSet实现。TreeSet是有序的Set集合。设置TreeSet的大小为3,保存三个最大的数。如果数组长度小于3,返回最大值,如果大于3,返回TreeSet中的第一个值。
class Solution {
public int thirdMax(int[] nums) {
TreeSet<Integer> set = new TreeSet<>();
for(Integer num:nums){
set.add(num);
if(set.size()>3){
set.remove(set.first());
}
}
return set.size()<3?set.last():set.first();
}
}
运行结果:
10.找到所有数组中缺失的数据
给定一个范围在 1 ≤ a[i] ≤ n ( n = 数组大小 ) 的 整型数组,数组中的元素一些出现了两次,另一些只出现一次。 找到所有在 [1, n] 范围之间没有出现在数组中的数字。
您能在不使用额外空间且时间复杂度为O(n)的情况下完成这个任务吗? 你可以假定返回的数组不算在额外空间内。
解题思路:
将数组中的每个数字对应一个下标,比如数字3对应下标2,并且把下标2上的数字变为负数,这样,最后哪个下标上的数字为正,就说明缺(下标+1)这个数字。
class Solution {
public List<Integer> findDisappearedNumbers(int[] nums) {
for(int i = 0;i < nums.length;i++){
int newIndex = Math.abs(nums[i])-1;
if(nums[newIndex] > 0){
nums[newIndex] *= -1;
}
}
List<Integer> list = new LinkedList<Integer>();
for(int i = 0;i < nums.length;i++){
if(nums[i] > 0){
list.add(i+1);
}
}
return list;
}
}
运行结果: