数组相关算法题(一)

数组相关算法题:

1 、二分查找

给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target  ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。

示例 1:

输入: nums = [-1,0,3,5,9,12], target = 9
输出: 4
解释: 9 出现在 nums 中并且下标为 4
示例 2:

输入: nums = [-1,0,3,5,9,12], target = 2
输出: -1
解释: 2 不存在 nums 中因此返回 -1
提示:

你可以假设 nums 中的所有元素是不重复的。
n 将在 [1, 10000]之间。
nums 的每个元素都将在 [-9999, 9999]之间。

class Solution {
    public int search(int[] nums, int target) {
          int left = 0, right = nums.length - 1,mid = 0;
            while(left <= right){
                mid = left + ((right -left) >> 1);
                if(nums[mid] == target){
                    return mid;
                }else if(nums[mid] > target){
                    right = mid - 1;
                }else{
                    left = mid + 1;
                }
            }

            return -1;
    }

2、移除元素

给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。

不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。

元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参作任何拷贝
int len = removeElement(nums, val);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}
 

示例 1:

输入:nums = [3,2,2,3], val = 3
输出:2, nums = [2,2]
解释:函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2。你不需要考虑数组中超出新长度后面的元素。例如,函数返回的新长度为 2 ,而 nums = [2,2,3,3] 或 nums = [2,2,0,0],也会被视作正确答案。
示例 2:

输入:nums = [0,1,2,2,3,0,4,2], val = 2
输出:5, nums = [0,1,4,0,3]
解释:函数应该返回新的长度 5, 并且 nums 中的前五个元素为 0, 1, 3, 0, 4。注意这五个元素可为任意顺序。你不需要考虑数组中超出新长度后面的元素。
 

提示:

0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100

此题使用双指针:快慢指针

class Solution {
    public int removeElement(int[] nums, int val) {
        int fastIndex=0,slowIndex=0;
        for(fastIndex = 0 ; fastIndex < nums.length ;  fastIndex ++ ){
            if(nums[fastIndex] != val){
                 nums[slowIndex] = nums[fastIndex];
                 slowIndex ++;
            }
        }
        return slowIndex;
    }
}

3、长度最小的子数组

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:

输入:target = 4, nums = [1,4,4]
输出:1
示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
 

提示:

1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
 

双for循环

时间复杂度为O(n^2)的写法
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int sum ,result = Integer.MAX_VALUE,sublength = 0 ;
        for(int i = 0 ; i < nums.length; i++){
            sum = 0;
             for(int j = i; j < nums.length; j++){
                sum+=nums[j];
                if(sum >= target){
                    sublength = j - i + 1;
                    result = result > sublength ? sublength : result;
                    break;
                }
             }
        }

       return result == Integer.MAX_VALUE ? 0 : result;
    }
}

 操作数组的滑动窗口写法

时间复杂度为O(n)的写法
class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        int sum=0 ,result = Integer.MAX_VALUE,sublength = 0 ;int j = 0;
        for(int i = 0 ; i < nums.length; i++){
            sum += nums[i];
            while(sum >= target){
                sublength = i - j + 1;
                result = result > sublength ? sublength : result;
                sum-=nums[j++];
            }
        }

       return result == Integer.MAX_VALUE ? 0 : result;
    }
}

4、螺旋矩阵

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix 。

示例 1:

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]


示例 2:输入:n = 1
输出:[[1]]
提示:

1 <= n <= 20

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] result = new int[n][n];

        int loop = n/2 , starX=0,starY=0,count = 1,offset=1;

        while(loop > 0){
            int i = starX,y = starY;

            //最上边从左到右
            for( ; y < n +starY - offset ; y++){
                result[i][y] = count ++;
            }

            //最右边上从到下
            for( ;i < n +starX - offset;i++ ){
                result[i][y] = count ++;
            }
            
            //最下边从右到左
            for( ; y > starY; y--){
                 result[i][y] = count ++;
            }

            //最z左边从下到上
            for( ; i > starX ; i--){
                 result[i][y] = count ++;
            }
            loop --;
            starX ++;
            starY ++;
            offset += 2;

        }

        if(n % 2 == 1){
            int mid = n / 2;
            result[mid][mid] = count ++;
        }
        return result;
    }
}

5 、删除有序数组中的重复项

给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。

不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

说明:

为什么返回数值是整数,但输出的答案是数组呢?

请注意,输入数组是以「引用」方式传递的,这意味着在函数里修改输入数组对于调用者是可见的。

你可以想象内部操作如下:

// nums 是以“引用”方式传递的。也就是说,不对实参做任何拷贝
int len = removeDuplicates(nums);

// 在函数里修改输入数组对于调用者是可见的。
// 根据你的函数返回的长度, 它会打印出数组中 该长度范围内 的所有元素。
for (int i = 0; i < len; i++) {
    print(nums[i]);
}
 
示例 1:

输入:nums = [1,1,2]
输出:2, nums = [1,2]
解释:函数应该返回新的长度 2 ,并且原数组 nums 的前两个元素被修改为 1, 2 。不需要考虑数组中超出新长度后面的元素。
示例 2:

输入:nums = [0,0,1,1,1,2,2,3,3,4]
输出:5, nums = [0,1,2,3,4]
解释:函数应该返回新的长度 5 , 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4 。不需要考虑数组中超出新长度后面的元素。

class Solution {
    public int removeDuplicates(int[] nums) {
            if( nums == null || nums.length == 0){
              return 0;
            }
            int slow = 0;
            for(int fast = 0 ; fast < nums.length -1 ; fast ++){
                if(nums[fast] != nums[fast+1]){
                    nums[++slow] = nums[fast+1];
                }
            }
            return slow + 1 ;
    }
}

6、搜索插入位置

给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。

你可以假设数组中无重复元素。

示例 1:

输入: [1,3,5,6], 5
输出: 2
示例 2:

输入: [1,3,5,6], 2
输出: 1
示例 3:

输入: [1,3,5,6], 7
输出: 4
示例 4:

输入: [1,3,5,6], 0
输出: 0

class Solution {
    public int searchInsert(int[] nums, int target) {
            for(int  i = 0 ; i < nums.length ; i++){
                if(nums[i] >= target){
                    return i;
                }
            }
            return nums.length;
    }
}

7、最大子序列和

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例 1:

输入:nums = [-2,1,-3,4,-1,2,1,-5,4]
输出:6
解释:连续子数组 [4,-1,2,1] 的和最大,为 6 。
示例 2:

输入:nums = [1]
输出:1
示例 3:

输入:nums = [0]
输出:0
示例 4:

输入:nums = [-1]
输出:-1
示例 5:

输入:nums = [-100000]
输出:-100000

解题思路:当前N 的值与前面K个值的和相加,如若前面k个值的和 < 0 ,则N 的值与前k个值的和相加是没有意义的,故求和的值会是从当前值算起。只有与正数值相加 才会得到更大的值

class Solution {
    public int maxSubArray(int[] nums) {
        int res = nums[0];
        int sum = 0;
        for (int num : nums) {
            if (sum > 0)
               sum += num;
            else
                sum = num;
            res = Math.max(res, sum);
        }
        return res;
    }
}

  8、加一

给定一个由 整数 组成的 非空 数组所表示的非负整数,在该数的基础上加一。

最高位数字存放在数组的首位, 数组中每个元素只存储单个数字。

你可以假设除了整数 0 之外,这个整数不会以零开头。

示例 1:

输入:digits = [1,2,3]
输出:[1,2,4]
解释:输入数组表示数字 123。
示例 2:

输入:digits = [4,3,2,1]
输出:[4,3,2,2]
解释:输入数组表示数字 4321。
示例 3:

输入:digits = [0]
输出:[1]

class Solution {
    public int[] plusOne(int[] digits) {
        for(int  i = digits.length -1 ; i >= 0 ; i--){
            if(digits[i] != 9){
                digits[i] ++;
                return digits;
            }

            digits[i] = 0;

        }
        int[] newDigits = new int[digits.length +1];
        newDigits[0] = 1;
        return newDigits;
    }
}

9、将有序数组转换为二叉搜索树

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。

高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。

示例 1:

数组相关算法题(一)_第1张图片


输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:

数组相关算法题(一)_第2张图片

示例 2:


输入:nums = [1,3]
输出:[3,1]
解释:[1,3] 和 [3,1] 都是高度平衡二叉搜索树。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    
public TreeNode sortedArrayToBST(int[] nums) {

       return getBST(nums,0,nums.length -1);
    }

     public static TreeNode getBST(int[] nums,int left,int right){
            if(left > right){
                return null;
            }
            TreeNode treeNode = new TreeNode();
            int mid = left + ((right - left)/2 );
            int midval = nums[mid];
            treeNode.val = midval ;
            treeNode.left = getBST(nums,left,mid -1);
            treeNode.right = getBST(nums,mid+1,right);
            return treeNode;
        }
}

10、杨辉三角

给定一个非负整数 numRows,生成杨辉三角的前 numRows 行。

在杨辉三角中,每个数是它左上方和右上方的数的和。

示例:

输入: 5
输出:
[
     [1],
    [1,1],
   [1,2,1],
  [1,3,3,1],
 [1,4,6,4,1]
]

class Solution {
    public List> generate(int numRows) {
        List> generateList = new ArrayList<>();
        for(int i = 0 ; i < numRows ; i++){
            List list = new ArrayList<>();
            for(int  j = 0 ; j <= i; j++){
                 
                 if(j == 0 || j == i)  {
                     list.add(1);
                 }else{
                     list.add(generateList.get(i-1).get(j-1)+generateList.get(i-1).get(j));
                 } 
                
            }
             generateList.add(list);
        }
        return generateList;
    }
}

11、杨辉三角2

给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。

在杨辉三角中,每个数是它左上方和右上方的数的和。

示例:

输入: 3
输出: [1,3,3,1]
进阶:

你可以优化你的算法到 O(k) 空间复杂度吗?

class Solution {
    public List getRow(int rowIndex) {
      
        List rowIndexList = new ArrayList();
        rowIndexList.add(1);
        if(rowIndex ==  0){         
            return rowIndexList;
        }
        
        List preRowList = getRow(rowIndex - 1);
        for(int  i = 0 ; i < preRowList.size() - 1; i ++){
            rowIndexList.add(preRowList.get(i) + preRowList.get(i+1));
        }
        rowIndexList.add(1);
        return rowIndexList;
    }
}

12、买股票的最佳时机

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

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

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

示例 1:

输入:[7,1,5,3,6,4]
输出:5
解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。
     注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。
示例 2:

输入:prices = [7,6,4,3,1]
输出:0
解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

class Solution {
    public int maxProfit(int[] prices) {
        int max = 0;
        int min = prices[0];

        for(int i = 1 ; i < prices.length ; i++){
            if(prices[i] < min){
                min = prices[i];
            }else{
                max =Math.max(max,prices[i] - min);
            }
        }
        return max;
    }
}

13、买卖股票的最佳时机2

给定一个数组 prices ,其中 prices[i] 是一支给定股票第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:

输入: prices = [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
     随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。
示例 2:

输入: prices = [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。
     注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。
示例 3:

输入: prices = [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。

class Solution {
    public int maxProfit(int[] prices) {
        int sum = 0;
        for(int i =1 ; i < prices.length ; i ++){
            int differ =  prices[i] - prices[i -1] ;
            if(differ > 0){
                sum += differ;
            }
        }

        return sum;
    }
}

14、只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

说明:

你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1:

输入: [2,2,1]
输出: 1
示例 2:

输入: [4,1,2,1,2]
输出: 4

使用异或的方式处理

4^1^2^1^2 相当于 (1^1)^(2^2)^4,(1^1)=0 ,(2^2) = 0 ,0^X = X;

class Solution {
    public int singleNumber(int[] nums) {
        int result = nums[0];
        for(int i = 1 ; i < nums.length ; i++){
            result = result^nums[i];
        }
        return result;
    }
}

15、 两数之和 输入有序数组

给定一个已按照 升序排列  的整数数组 numbers ,请你从数组中找出两个数满足相加之和等于目标数 target 。

函数应该以长度为 2 的整数数组的形式返回这两个数的下标值。numbers 的下标 从 1 开始计数 ,所以答案数组应当满足 1 <= answer[0] < answer[1] <= numbers.length 。

你可以假设每个输入只对应唯一的答案,而且你不可以重复使用相同的元素。

 
示例 1:

输入:numbers = [2,7,11,15], target = 9
输出:[1,2]
解释:2 与 7 之和等于目标数 9 。因此 index1 = 1, index2 = 2 。
示例 2:

输入:numbers = [2,3,4], target = 6
输出:[1,3]
示例 3:

输入:numbers = [-1,0], target = -1
输出:[1,2]

class Solution {
    public int[] twoSum(int[] numbers, int target) {
       int i = 0, j = numbers.length - 1;  //初始化左右指针
        while(i <= j) {
            if(numbers[i] + numbers[j] == target)   //和等于目标值
                return new int[]{i + 1, j + 1};
            else if(numbers[i] + numbers[j] < target)   
            //和小于目标值,我们将左指针往右移,使得和变大
                i++;
            else     //大于目标值,我们将右指针往左移,使得和变小
                j--;
        }
        return new int[0];

    }
}

16、 多数元素

给定一个大小为 n 的数组,找到其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例 1:

输入:[3,2,3]
输出:3
示例 2:

输入:[2,2,1,1,1,2,2]
输出:2
 

进阶:

尝试设计时间复杂度为 O(n)、空间复杂度为 O(1) 的算法解决此问题。

使用摩尔算法 :

class Solution {
    public int majorityElement(int[] nums) {
        int count = 1;
        int result = nums[0];

        for(int i = 1 ;i < nums.length ; i++){
            if(nums[i] == result){
                count ++;
            }else{
                count --;
            }

            if(count == 0){
                result = nums[i];
                count=1;
            }
        }
        return result;
    }
}

17、 存在重复元素

给定一个整数数组,判断是否存在重复元素。

如果存在一值在数组中出现至少两次,函数返回 true 。如果数组中每个元素都不相同,则返回 false 。

示例 1:

输入: [1,2,3,1]
输出: true
示例 2:

输入: [1,2,3,4]
输出: false
示例 3:

输入: [1,1,1,3,3,4,3,2,4,2]
输出: true

方式一

class Solution {
    public boolean containsDuplicate(int[] nums) {
      return Arrays.stream(nums).distinct().count() != nums.length;
    }
}

方式二

class Solution {
    public boolean containsDuplicate(int[] nums) {
        Map map = new HashMap();
        for(int i = 0 ; i < nums.length ; i++){
           if(map.containsKey(nums[i])){
               return true;
           }else{
               map.put(nums[i],i);
           }
        }
       return false;
    }
}

 方式三

class Solution {
    public boolean containsDuplicate(int[] nums) {
        Set set = new HashSet<>();
        for(int i = 0 ; i < nums.length ; i++){
           set.add(nums[i]);
        }
        if(set.size() == nums.length) return false;    
        return true;
    }
}

18、存在重复元素2

给定一个整数数组和一个整数 k,判断数组中是否存在两个不同的索引 i 和 j,使得 nums [i] = nums [j],并且 i 和 j 的差的 绝对值 至多为 k。

示例 1:

输入: nums = [1,2,3,1], k = 3
输出: true
示例 2:

输入: nums = [1,0,1,1], k = 1
输出: true
示例 3:

输入: nums = [1,2,3,1,2,3], k = 2
输出: false

class Solution {
    public boolean containsNearbyDuplicate(int[] nums, int k) {
        Map map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if(map.containsKey(nums[i]) && Math.abs(map.get(nums[i]) - i ) <= k){
                return true;
            }else{
                map.put(nums[i],i);
            }
        }
        return false;
    }
}

19、丢失的数字

给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

进阶:

你能否实现线性时间复杂度、仅使用额外常数空间的算法解决此问题?
 

示例 1:

输入:nums = [3,0,1]
输出:2
解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。
示例 2:

输入:nums = [0,1]
输出:2
解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2 是丢失的数字,因为它没有出现在 nums 中。
示例 3:

输入:nums = [9,6,4,2,3,5,7,0,1]
输出:8
解释:n = 9,因为有 9 个数字,所以所有的数字都在范围 [0,9] 内。8 是丢失的数字,因为它没有出现在 nums 中。
示例 4:

输入:nums = [0]
输出:1
解释:n = 1,因为有 1 个数字,所以所有的数字都在范围 [0,1] 内。1 是丢失的数字,因为它没有出现在 nums 中。

class Solution {
    public int missingNumber(int[] nums) {
        int sum =0;
        int numlength = nums.length;
        for(int i = 0 ; i < numlength ; i++){
           sum +=nums[i];
        }

        return numlength * (numlength + 1) / 2  -  sum;
    }
}

class Solution {
    public int missingNumber(int[] nums) {
        Arrays.sort(nums);
        for(int i = 0 ; i < nums.length ; i++){
            if(nums[i] != i) return i;

        }
        return nums.length;
    }
}

20、两个数组的交集

给定两个数组,编写一个函数来计算它们的交集。

示例 1:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
示例 2:

输入:nums1 = [4,9,5], nums2 = [9,4,9,8,4]
输出:[4,9]
 

说明:

输出结果中每个元素出现的次数,应与元素在两个数组中出现次数的最小值一致。
我们可以不考虑输出结果的顺序。

解题思路:

创建一个指针 i 指向 nums1 数组首位,指针 j 指向nums2 数组首位。
创建一个临时栈,用于存放结果集。
开始比较指针 i 和指针 j 的值大小,若两个值不等,则数字小的指针,往右移一位。
若指针 i和指针 j 的值相等,则将交集压入栈。
若 nums1 或 nums2 有一方遍历结束,代表另一方的剩余值,都是唯一存在,且不会与之产生交集的。

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
          Arrays.sort(nums1);
        Arrays.sort(nums2);
        int length1 = nums1.length, length2 = nums2.length;
        int[] intersection = new int[Math.min(length1, length2)];
        int index1 = 0, index2 = 0, index = 0;
        while (index1 < length1 && index2 < length2) {
            if (nums1[index1] < nums2[index2]) {
                index1++;
            } else if (nums1[index1] > nums2[index2]) {
                index2++;
            } else {
                intersection[index] = nums1[index1];
                index1++;
                index2++;
                index++;
            }
        }
        return Arrays.copyOfRange(intersection, 0, index);

    }
}

21、第三大的数

给你一个非空数组,返回此数组中 第三大的数 。如果不存在,则返回数组中最大的数。

示例 1:

输入:[3, 2, 1]
输出:1
解释:第三大的数是 1 。
示例 2:

输入:[1, 2]
输出:2
解释:第三大的数不存在, 所以返回最大的数 2 。
示例 3:

输入:[2, 2, 3, 1]
输出:1
解释:注意,要求返回第三大的数,是指在所有不同数字中排第三大的数。
此例中存在两个值为 2 的数,它们都排第二。在所有不同数字中排第三大的数为 1 。
 

提示:

1 <= nums.length <= 104
-231 <= nums[i] <= 231 - 1
 

进阶:你能设计一个时间复杂度 O(n) 的解决方案吗?

class Solution {
    public int thirdMax(int[] nums) {
        long minValue = (long)Integer.MIN_VALUE -1;
        long maxFirst = minValue;
        long maxSecond = minValue;
        long maxThird = minValue;
        for(int i = 0 ; i< nums.length ; i++){
            if(nums[i] > maxFirst){
                maxThird = maxSecond;
                maxSecond = maxFirst;
                maxFirst = nums[i];   
            }else if(maxSecond < nums[i] &&  nums[i] < maxFirst ){
                   maxThird = maxSecond;
                   maxSecond = nums[i];
            }else if(maxThird < nums[i] && nums[i] < maxSecond){
                maxThird = nums[i];
            }
        }

        return (int)(maxThird == minValue ? maxFirst: maxThird);
    }
}

22、找到所有数组中消失的数字

给你一个含 n 个整数的数组 nums ,其中 nums[i] 在区间 [1, n] 内。请你找出所有在 [1, n] 范围内但没有出现在 nums 中的数字,并以数组的形式返回结果。

示例 1:

输入:nums = [4,3,2,7,8,2,3,1]
输出:[5,6]
示例 2:

输入:nums = [1,1]
输出:[2]
 

提示:

n == nums.length
1 <= n <= 105
1 <= nums[i] <= n
进阶:你能在不使用额外空间且时间复杂度为 O(n) 的情况下解决这个问题吗? 你可以假定返回的数组不算在额外空间内

class Solution {
     public List findDisappearedNumbers(int[] nums) {
        int n = nums.length;
        List result = new ArrayList<>();
        for (int i = 0; i < n; i++) {
            int x = (nums[i] - 1) % n;  // 找到数字x存放在顺序数组中的下标
            nums[x] += n;
        }
        for (int i = 0; i < n; i++) {
            if (nums[i] <= n) 
                result.add(i + 1);
        }
        return result;
    }

}

23、最小操作次数使数组元素相等

给定一个长度为 n 的 非空 整数数组,每次操作将会使 n - 1 个元素增加 1。找出让数组所有元素相等的最小操作次数。

示例:

输入:
[1,2,3]
输出:
3
解释:
只需要3次操作(注意每次操作会增加两个元素的值):
[1,2,3]  =>  [2,3,3]  =>  [3,4,3]  =>  [4,4,4]

此题转换下思路就是 每个数要减多少个1 才能等于最小数  

[1,2,3] 总共三次的计算方式
2 -1 = 1次
3-1 =2 次

[1,2,3,4] 总共六次的计算方式
2-1 = 1 次
3-1 = 2次
4-1 = 3次
class Solution {
    public int minMoves(int[] nums) {
        int min=nums[0];int sum=0;
        for(int n:nums){
            min=min

24、分发饼干

假设你是一位很棒的家长,想要给你的孩子们一些小饼干。但是,每个孩子最多只能给一块饼干。

对每个孩子 i,都有一个胃口值 g[i],这是能让孩子们满足胃口的饼干的最小尺寸;并且每块饼干 j,都有一个尺寸 s[j] 。如果 s[j] >= g[i],我们可以将这个饼干 j 分配给孩子 i ,这个孩子会得到满足。你的目标是尽可能满足越多数量的孩子,并输出这个最大数值。

 
示例 1:

输入: g = [1,2,3], s = [1,1]
输出: 1
解释: 
你有三个孩子和两块小饼干,3个孩子的胃口值分别是:1,2,3。
虽然你有两块小饼干,由于他们的尺寸都是1,你只能让胃口值是1的孩子满足。
所以你应该输出1。
示例 2:

输入: g = [1,2], s = [1,2,3]
输出: 2
解释: 
你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
你拥有的饼干数量和尺寸都足以让所有孩子满足。

使用贪心算法

class Solution {
    public int findContentChildren(int[] g, int[] s) {
        Arrays.sort(g);
        Arrays.sort(s);
        int count = 0;
        int start = 0;
        for(int i = 0 ; i < s.length && start < g.length; i++){
            if(s[i] >= g[start]){
                start ++;
                count ++;
            }
        }
        return count;
    }
}

25、岛屿的周长

给定一个 row x col 的二维网格地图 grid ,其中:grid[i][j] = 1 表示陆地, grid[i][j] = 0 表示水域。

网格中的格子 水平和垂直 方向相连(对角线方向不相连)。整个网格被水完全包围,但其中恰好有一个岛屿(或者说,一个或多个表示陆地的格子相连组成的岛屿)。

岛屿中没有“湖”(“湖” 指水域在岛屿内部且不和岛屿周围的水相连)。格子是边长为 1 的正方形。网格为长方形,且宽度和高度均不超过 100 。计算这个岛屿的周长。

示例 1:

数组相关算法题(一)_第3张图片

输入:grid = [[0,1,0,0],[1,1,1,0],[0,1,0,0],[1,1,0,0]]
输出:16
解释:它的周长是上面图片中的 16 个黄色的边
示例 2:

输入:grid = [[1]]
输出:4
示例 3:

输入:grid = [[1,0]]
输出:4

grid[i][y]为 1 时 周长是4 当上下左右有陆地的话就要减1

class Solution {
    public int islandPerimeter(int[][] grid) {
        int sum = 0 ;
        for(int i = 0 ; i < grid.length ; i++){
            for(int j = 0 ; j < grid[i].length ; j++){
               if(grid[i][j] == 1){
                 int count = 4;
                 if( (i - 1) >= 0 && grid[i -1][j] == 1){
                    count -- ;
                
                 }

                 if((i + 1) < grid.length && grid[i + 1][j] == 1){
                    count -- ;
                 }

                 if((j - 1) >= 0 && grid[i][j - 1] == 1){
                    count -- ;
                 }

                 if((j + 1) < grid[i].length && grid[i][j + 1] == 1){
                    count -- ;
                 }
                sum += count;
               }
            }
        }

        return sum;
    }
}

26、最大连续1的个数

给定一个二进制数组, 计算其中最大连续 1 的个数。

示例:

输入:[1,1,0,1,1,1]
输出:3
解释:开头的两位和最后的三位都是连续 1 ,所以最大连续 1 的个数是 3.
 

提示:

输入的数组只包含 0 和 1 。
输入数组的长度是正整数,且不超过 10,000。

遇到1 count加1  遇到0 count清0

class Solution {
    public int findMaxConsecutiveOnes(int[] nums) {
        int fastIndex = 0;
        int max = 0;
        int count = 0;
        for(int i =0 ; i < nums.length ; i++){
            if(nums[i] == 1){
               count ++;
               max = count > max ? count : max;
            }else{
                count = 0;
            }
        }
        return max;
    }
}

27、提莫攻击

在《英雄联盟》的世界中,有一个叫 “提莫” 的英雄,他的攻击可以让敌方英雄艾希(编者注:寒冰射手)进入中毒状态。现在,给出提莫对艾希的攻击时间序列和提莫攻击的中毒持续时间,你需要输出艾希的中毒状态总时长。

你可以认为提莫在给定的时间点进行攻击,并立即使艾希处于中毒状态。

示例1:

输入: [1,4], 2
输出: 4
原因: 第 1 秒初,提莫开始对艾希进行攻击并使其立即中毒。中毒状态会维持 2 秒钟,直到第 2 秒末结束。
第 4 秒初,提莫再次攻击艾希,使得艾希获得另外 2 秒中毒时间。
所以最终输出 4 秒。
示例2:

输入: [1,2], 2
输出: 3
原因: 第 1 秒初,提莫开始对艾希进行攻击并使其立即中毒。中毒状态会维持 2 秒钟,直到第 2 秒末结束。
但是第 2 秒初,提莫再次攻击了已经处于中毒状态的艾希。
由于中毒状态不可叠加,提莫在第 2 秒初的这次攻击会在第 3 秒末结束。
所以最终输出 3 。

class Solution {
    public int findPoisonedDuration(int[] timeSeries, int duration) {
        int sum = duration;
        for(int i = 1 ; i < timeSeries.length ; i++){
            if(timeSeries[i] - timeSeries[i -1] >= duration ){
                sum +=duration;
            }else{
                sum +=timeSeries[i] - timeSeries[i -1];
            }
        }
        return sum;
    }
}

28、键盘行

给你一个字符串数组 words ,只返回可以使用在 美式键盘 同一行的字母打印出来的单词。键盘如下图所示。

美式键盘 中:

第一行由字符 "qwertyuiop" 组成。
第二行由字符 "asdfghjkl" 组成。
第三行由字符 "zxcvbnm" 组成。

示例 1:

输入:words = ["Hello","Alaska","Dad","Peace"]
输出:["Alaska","Dad"]
示例 2:

输入:words = ["omk"]
输出:[]
示例 3:

输入:words = ["adsdf","sfd"]
输出:["adsdf","sfd"]

class Solution {
    public String[] findWords(String[] words) {
        String s1 = "qwertyuiop";
        String s2 = "asdfghjkl";
        String s3 = "zxcvbnm";
        ArrayList list = new ArrayList<>();

        for(String str: words){
            int strLength = str.length();
            int n1=0,n2=0,n3=0;
            for(int i=0;i

29、 相对名次

给出 N 名运动员的成绩,找出他们的相对名次并授予前三名对应的奖牌。前三名运动员将会被分别授予 “金牌”,“银牌” 和“ 铜牌”("Gold Medal", "Silver Medal", "Bronze Medal")。

(注:分数越高的选手,排名越靠前。)

输入: [5, 4, 3, 2, 1]
输出: ["Gold Medal", "Silver Medal", "Bronze Medal", "4", "5"]
解释: 前三名运动员的成绩为前三高的,因此将会分别被授予 “金牌”,“银牌”和“铜牌” ("Gold Medal", "Silver Medal" and "Bronze Medal").
余下的两名运动员,我们只需要通过他们的成绩计算将其相对名次即可。

  1. N 是一个正整数并且不会超过 10000。
  2. 所有运动员的成绩都不相同
class Solution {
    public String[] findRelativeRanks(int[] score) {
       int[][] map = new int[score.length][2];
        for(int i = 0; i < score.length; i++) {
            map[i][0] = score[i];
            map[i][1] = i;
        }
        Arrays.sort(map, (a, b) -> b[0] - a[0]);
        String[] res = new String[score.length];
        for(int i = 0; i < map.length; i++) {
            if(i == 0) {
                res[map[i][1]] = "Gold Medal";
            } else if(i == 1) {
                res[map[i][1]] = "Silver Medal";
            } else if(i == 2) {
                res[map[i][1]] = "Bronze Medal";
            } else {
                res[map[i][1]] = "" + (i + 1);
            }
        }
        return res;
    }
}

30、 数组拆分1

给定长度为 2n 的整数数组 nums ,你的任务是将这些数分成 n 对, 例如 (a1, b1), (a2, b2), ..., (an, bn) ,使得从 1 到 n 的 min(ai, bi) 总和最大。

返回该 最大总和 。

示例 1:

输入:nums = [1,4,3,2]
输出:4
解释:所有可能的分法(忽略元素顺序)为:
1. (1, 4), (2, 3) -> min(1, 4) + min(2, 3) = 1 + 2 = 3
2. (1, 3), (2, 4) -> min(1, 3) + min(2, 4) = 1 + 2 = 3
3. (1, 2), (3, 4) -> min(1, 2) + min(3, 4) = 1 + 3 = 4
所以最大总和为 4
示例 2:

输入:nums = [6,2,6,5,1,2]
输出:9
解释:最优的分法为 (2, 1), (2, 5), (6, 6). min(2, 1) + min(2, 5) + min(6, 6) = 1 + 2 + 6 = 9

class Solution {
    public int arrayPairSum(int[] nums) {
            Arrays.sort(nums);
            int sum = 0;
            for(int i =0 ; i < nums.length ; i+=2){   
                    sum+=nums[i];
            }
            return sum;
    }
}

31、 重塑矩阵

在MATLAB中,有一个非常有用的函数 reshape,它可以将一个矩阵重塑为另一个大小不同的新矩阵,但保留其原始数据。

给出一个由二维数组表示的矩阵,以及两个正整数r和c,分别表示想要的重构的矩阵的行数和列数。

重构后的矩阵需要将原始矩阵的所有元素以相同的行遍历顺序填充。

如果具有给定参数的reshape操作是可行且合理的,则输出新的重塑矩阵;否则,输出原始矩阵。

示例 1:

输入: 
nums = 
[[1,2],
 [3,4]]
r = 1, c = 4
输出: 
[[1,2,3,4]]
解释:
行遍历nums的结果是 [1,2,3,4]。新的矩阵是 1 * 4 矩阵, 用之前的元素值一行一行填充新矩阵。
示例 2:

输入: 
nums = 
[[1,2],
 [3,4]]
r = 2, c = 4
输出: 
[[1,2],
 [3,4]]
解释:
没有办法将 2 * 2 矩阵转化为 2 * 4 矩阵。 所以输出原矩阵。

class Solution {
    public int[][] matrixReshape(int[][] mat, int r, int c) {
        if(r*c != mat.length*mat[0].length){
                    return  mat;
        }

        int x=0,y=0;
        int[][] reshape = new int[r][c];
        for (int i = 0; i < mat.length; i++) {
            for(int j = 0; j < mat[i].length; j++){
                 reshape[x][y] = mat[i][j];
                 y++;
                if(y == c){
                    x++;
                    y = 0;
                }    
            }

        }
        return reshape;
    }
}

32、 分糖果

给定一个偶数长度的数组,其中不同的数字代表着不同种类的糖果,每一个数字代表一个糖果。你需要把这些糖果平均分给一个弟弟和一个妹妹。返回妹妹可以获得的最大糖果的种类数。

示例 1:

输入: candies = [1,1,2,2,3,3]
输出: 3
解析: 一共有三种种类的糖果,每一种都有两个。
     最优分配方案:妹妹获得[1,2,3],弟弟也获得[1,2,3]。这样使妹妹获得糖果的种类数最多。
示例 2 :

输入: candies = [1,1,2,3]
输出: 2
解析: 妹妹获得糖果[2,3],弟弟获得糖果[1,1],妹妹有两种不同的糖果,弟弟只有一种。这样使得妹妹可以获得的糖果种类数最多。

class Solution {
    public int distributeCandies(int[] candyType) {
        Set s  = new HashSet();
        int eachNum = candyType.length/2;
        
        for (int i : candyType) {
            s.add(i);
        }
        if(s.size() >= eachNum){
            return eachNum;
        }else{
            return  s.size();
        }
    }
}

33、 最长和谐子序列

和谐数组是指一个数组里元素的最大值和最小值之间的差别 正好是 1 。

现在,给你一个整数数组 nums ,请你在所有可能的子序列中找到最长的和谐子序列的长度。

数组的子序列是一个由数组派生出来的序列,它可以通过删除一些元素或不删除元素、且不改变其余元素的顺序而得到。

示例 1:

输入:nums = [1,3,2,2,5,2,3,7]
输出:5
解释:最长的和谐子序列是 [3,2,2,2,3]
示例 2:

输入:nums = [1,2,3,4]
输出:2
示例 3:

输入:nums = [1,1,1,1]
输出:0

使用双指针的方式

class Solution {
    public int findLHS(int[] nums) {
        Arrays.sort(nums);
        int max = 0;
        for(int i = 0 ,j = 0; i < nums.length ; i++){
            while(nums[i] - nums[j] > 1){
                j++;
            }
            
            if(nums[i] - nums[j] == 1){
                max = Math.max(max,i-j+1);
            }
        }
       return max;
        }
}

34、范围求和

给定一个初始元素全部为 0,大小为 m*n 的矩阵 M 以及在 M 上的一系列更新操作。

操作用二维数组表示,其中的每个操作用一个含有两个正整数 a 和 b 的数组表示,含义是将所有符合 0 <= i < a 以及 0 <= j < b 的元素 M[i][j] 的值都增加 1。

在执行给定的一系列操作后,你需要返回矩阵中含有最大整数的元素个数。

示例 1:

输入: 
m = 3, n = 3
operations = [[2,2],[3,3]]
输出: 4
解释: 
初始状态, M = 
[[0, 0, 0],
 [0, 0, 0],
 [0, 0, 0]]

执行完操作 [2,2] 后, M = 
[[1, 1, 0],
 [1, 1, 0],
 [0, 0, 0]]

执行完操作 [3,3] 后, M = 
[[2, 2, 1],
 [2, 2, 1],
 [1, 1, 1]]

M 中最大的整数是 2, 而且 M 中有4个值为2的元素。因此返回 4。

此题只需要记录交集区域的右下角即可

class Solution {
    public int maxCount(int m, int n, int[][] ops) {
        for(int i = 0 ; i < ops.length ;i++){
            m = Math.min(ops[i][0],m);
            n = Math.min(ops[i][1],n);
        }

        return m *n  ;
    }
}

35、两个列表的最小索引综总和

假设Andy和Doris想在晚餐时选择一家餐厅,并且他们都有一个表示最喜爱餐厅的列表,每个餐厅的名字用字符串表示。

你需要帮助他们用最少的索引和找出他们共同喜爱的餐厅。 如果答案不止一个,则输出所有答案并且不考虑顺序。 你可以假设总是存在一个答案。

示例 1:

输入:
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["Piatti", "The Grill at Torrey Pines", "Hungry Hunter Steakhouse", "Shogun"]
输出: ["Shogun"]
解释: 他们唯一共同喜爱的餐厅是“Shogun”。
示例 2:

输入:
["Shogun", "Tapioca Express", "Burger King", "KFC"]
["KFC", "Shogun", "Burger King"]
输出: ["Shogun"]
解释: 他们共同喜爱且具有最小索引和的餐厅是“Shogun”,它有最小的索引和1(0+1)。

class Solution {
    public String[] findRestaurant(String[] list1, String[] list2) {
             List < String > res = new ArrayList < > ();
        for (int sum = 0; sum < list1.length + list2.length - 1; sum++) {
            for (int i = 0; i <= sum; i++) {
                if (i < list1.length && sum - i < list2.length && list1[i].equals(list2[sum - i]))
                    res.add(list1[i]);
            }
            if (res.size() > 0)
                break;
        }
        return res.toArray(new String[res.size()]);

    }
}

36、种花问题 

假设有一个很长的花坛,一部分地块种植了花,另一部分却没有。可是,花不能种植在相邻的地块上,它们会争夺水源,两者都会死去。

给你一个整数数组  flowerbed 表示花坛,由若干 0 和 1 组成,其中 0 表示没种植花,1 表示种植了花。另有一个数 n ,能否在不打破种植规则的情况下种入 n 朵花?能则返回 true ,不能则返回 false。

示例 1:

输入:flowerbed = [1,0,0,0,1], n = 1
输出:true
示例 2:

输入:flowerbed = [1,0,0,0,1], n = 2
输出:false

class Solution {
    public boolean canPlaceFlowers(int[] flowerbed, int n) {
      for(int i=0;i

37、 三个数的最大乘积

给你一个整型数组 nums ,在数组中找出由三个数组成的最大乘积,并输出这个乘积。

示例 1:

输入:nums = [1,2,3]
输出:6
示例 2:

输入:nums = [1,2,3,4]
输出:24
示例 3:

输入:nums = [-1,-2,-3]
输出:-6

class Solution {
    public int maximumProduct(int[] nums) {
        Arrays.sort(nums);
        int n = nums.length;
        return Math.max(nums[0] * nums[1] * nums[n - 1], nums[n - 3] * nums[n - 2] * nums[n - 1]);

    }
}

38、子数组最大平均数

给定 n 个整数,找出平均数最大且长度为 k 的连续子数组,并输出该最大平均数。

示例:

输入:[1,12,-5,-6,50,3], k = 4
输出:12.75
解释:最大平均数 (12-5-6+50)/4 = 51/4 = 12.75

使用滑动窗口解决

class Solution {
    public double findMaxAverage(int[] nums, int k) {
          double sum = 0;
        for(int i = 0 ; i < k ;i ++){
            sum += nums[i];
        }
        double max = sum;
        int len = nums.length;
        for(int i = k ; i < len ;i ++){
            sum = sum - nums[i - k ]+nums[i];
            max = Math.max(max,sum);
        }
        return max/k;
    }
}

来源力扣(LeetCode)
链接:https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree

你可能感兴趣的:(算法与数据结构,算法,数据结构,java)