LeetCode初级算法-数组

初级算法

一、删除排序数组的重复项

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

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

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

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

/**
* count记录元素重复数 == 数组元素向前移动的步数
*/
 public int removeDuplicates(int[] nums) {
        int count = 0;
        for (int i = 1; i < nums.length; i++) {
            if(nums[i] == nums[i - 1]){
                count ++;
            }else {
                nums[i - count] = nums[i];
            }
        }
        return nums.length - count;
    }

二、买卖股票的最佳时机

给定一个数组 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

解法:

 public static int maxProfit(int[] prices){
        int total = 0;
        for (int i = 0; i < prices.length -1; i++) {
            //只需要计算低进高出的部分即可
            if(prices[i] <= prices[i + 1]){
                total = total + prices[i + 1] - prices[i];
            }
        }
        return total;
    }

三、旋转数组

问题:数组中元素向右轮转k个位置,其中k是非负数

案例1:
int[] array = {1,2,3,4,5,6,7,8,9,10};
k 旋转位数

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

public static int[] xuanZhuan(int[] array,int k){
        int[] temp = array.clone();
        for (int i = 0; i < array.length; i++) {
            int a = (i + k) % array.length;
            array[a] = temp[i];
        }
        return array;
    }

四、存在重复元素

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

如果存在一值在数组中出现至少两次,函数返回 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

解法1:暴力

public static boolean method(int[] array){
        if(array == null){
            return true;
        }
        for (int i = 0; i < array.length; i++) {
            for (int j = i + 1; j < array.length; j++) {
                if(array[j] == array[i]){
                    return true;
                }
            }
        }
        return false;
    }

解法2:
利用set集合特性
set中不能有重复的元素,添加相同元素失败

 public static boolean containsDuplicate(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for (int num : nums) {
            if (!set.add(num))
                return true;
        }
        return false;
    }

解法3:
先排序后比较前后元素是否一致

 public static boolean containsDuplicate(int[] nums) {
        Arrays.sort(nums);
        for(int i = 0; i < nums.length - 1; i++) {
            if (nums[i] == nums[i + 1]) {
                return true;
            }
        }
        return false;
    }

五、只出现一次的数字

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

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

思路:使用异或运算,将所有值进行异或

public int singleNumber(int[] nums) {
        int reduce = 0;
        for (int num : nums) {
            reduce =  reduce ^ num;
        }
        return reduce;
    }

六、两个数组的交集

给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。

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

思路:先对两个数组进行排序,后判断

public static int[] intersect(int[] nums1, int[] nums2) {
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        ArrayList<Integer> list = new ArrayList<>();
        int i = 0,j = 0;
        while (i < nums1.length && j <nums2.length) {
            if(nums1[i] < nums2[j]){
                i ++;
            }else if(nums1[i] > nums2[j]){
                j ++;
            }else {
                list.add(nums1[i]);
                i ++;
                j ++;
            }
        }
        int[] target = new int[list.size()];
        for (int z = 0; z < list.size(); z++) {
            target[z] = list.get(z);
        }
        return target;
    }

七、加一

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

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

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

示例:
输入:digits = [1,2,3]
输出:[1,2,4]
解释:输入数组表示数字 123。
数组所有元素看成是一个数字:123 + 1 = 124
9 + 1 = 10
99 + 1 = 100
235 + 1 = 236

解决:

public static int[] plusOne(int[] digits) {
        for (int i = digits.length - 1; i >= 0; i--) {
            //末位元素=9 则置0
            if (digits[i] == 9) {
                digits[i] = 0;
            } else {
                //元素不等于9 则加1
                digits[i]++;
                return digits;
            }
        }
        //元素全为9 则扩充一位 首位置1
        int[] temp = new int[digits.length + 1];
        temp[0] = 1;
        return temp;
    }

八、移动零

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。

示例:
输入: [0,1,0,3,12]
输出: [1,3,12,0,0]

解法1:

 public static void moveZeroes(int[] nums) {
        //记录0出现个数
        int pos = 0;
        for (int i = 0; i < nums.length; i++) {
            if(nums[i] == 0){
                pos ++;
            }else if(pos > 0){
                //元素向前移动
                nums[i - pos] = nums[i];
            }
        }
        if(pos > 0){
            //最后元素置0
            for (int i = 1; i <= pos; i++) {
                nums[nums.length - i] = 0;
            }
        }
    }

解法2:

public static void moveZeroes2(int[] nums) {
        int pos = 0;
        //非0元素向前移动
        for (int i = 0; i < nums.length; i++) {
            if(nums[i] != 0){
                nums[pos ++] = nums[i];
            }
        }
        //最后num.length - pos 个的元素置0
        while(pos < nums.length){
            nums [pos++] = 0;
        }
    }

九、两数之和

给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target 的那 两个 整数,并返回它们的数组下标。

你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。

你可以按任意顺序返回答案。

实例1:
输入:nums = [2,7,11,15], target = 9
输出:[0,1]
解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。

解法1:暴力算法

//暴力算法
    public static int[] twoSum(int[] nums, int target){
        for (int i = 0; i < nums.length; i++) {
            for (int j = i + 1; j < nums.length; j++) {
               if(nums[i] + nums[j] == target){
                   return new int[]{i,j};
               }
            }
        }
        return new int[]{-1,-1};
    }

解法2:HashMap
思路:
新建一个HashMap存储元素
存储方式:key(存储元素值):nums[i],value(存储数组下标):i
判断条件 m.get(target - nums[i]) != null,其中target - nums[i]得到是与之匹配的第二个元素值,假如能HashMap中找到对应的key则说明存在该两个元素之和等于target,同时也可得到对应元素的数组下标。

    public int[] twoSum(int[] nums, int target) {
        Map<Integer, Integer> m = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (m.get(target - nums[i]) != null) {
                return new int[]{m.get(target - nums[i]), i};
            }
            m.put(nums[i], i);
        }
        return new int[]{0, 0};
    }

十、有效的数独

请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 ,验证已经填入的数字是否有效即可。

数字 1-9 在每一行只能出现一次。
数字 1-9 在每一列只能出现一次。
数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。(请参考示例图)

注意:

一个有效的数独(部分已被填充)不一定是可解的。
只需要根据以上规则,验证已经填入的数字是否有效即可。
空白格用 ‘.’ 表示。

示例1:
输入:
 char[][] board  = {{'8','3','.','.','7','.','.','.','.'}
                        ,{'6','.','.','1','9','5','.','.','.'}
                        ,{'.','9','8','.','.','.','.','6','.'}
                        ,{'8','.','.','.','6','.','.','.','3'}
                        ,{'4','.','.','8','.','3','.','.','1'}
                        ,{'7','.','.','.','2','.','.','.','6'}
                        ,{'.','6','.','.','.','.','2','8','.'}
                        ,{'.','.','.','4','1','9','.','.','5'}
                        ,{'.','.','.','.','8','.','.','7','9'}};

输出:false

解法1:暴力解
思路:

  • line col box三张二维表作用是记录元素占用的位置
  • line表可以看做是原board[][]字符数组表
  • col表的行可以当做是line表中的列
  • box表的行可以看做是,原board[][]字符数组的3x3单元格(9x9宫格分成9个3x3单元格,从左往右按顺序排列)
  • 单元格如下表示:
  • pos0,pos1,pos2,
  • pos3,pos4,pos5,
  • pos6,pos7,pos8
  • 三张表元素按照指定的排序规则,排序在表内
  • 即相同元素的排序位置是固定的
  • 举个例子,在board[0][]字符数组第一行内有两个相同的元素[,9,3,4,6,8,9]
  • 可以看出上述有相同元素9,即board[0][1] = 9 ,board[0][8] = 9
  • 我们根据排序规则 int pos = board[i][j] - ‘1’;
  • pos = board[0][1] - ‘1’ = 8
  • pos = board[0][8]- ‘1’ = 8
  • 得到pos都是等于8,所以当第一次位置未被占用时,board[0][1]的元素占用该位置,
  • 在执行到board[0][8]时,发现位置已经被占用,所以这是一个无效的数独
public static boolean isValidSudoku(char[][] board){
        //存储行的二维数组
        int[][] line = new int[board.length][board[0].length];
        //存储列的二维数组
        int[][] col = new int[board.length][board[0].length];
        //存储单元的二维数组
        int[][] box = new int[board.length][board[0].length];

        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[0].length; j++) {
                //board二维字符数组中'.'表示没有元素,所以可以直接跳过
                if(board[i][j] == '.')continue;
                //数组下标是0-8 所以pos代表的是排序后元素的位置
                //board[i][j] - '1'的区间是[0-8](不懂的小伙伴可以查看ASCII表对应值),对应这排序后的数组下标
                int pos = board[i][j] - '1';
                //首先将9x9的宫格分成9个3x3的单元格,从左到右排序
                //boxIndex代表的是从左到右的单元格的位置,boxIndex的范围是[0,8]
                int boxIndex = i/3 * 3 + j/3;
                //判断二维数组中位置是否已经被占用(二维数组中没有元素的值默认为0)
                if((line[i][pos] != 0) || (col[j][pos] != 0) || (box[boxIndex][pos] != 0))return false;
                //位置没有被占用,即可设置固定值 1 表示该位置已经被占用
                line[i][pos] = col[j][pos] = box[boxIndex][pos] = 1;
            }
        }
        return true;
    }

十一、旋转图像

给定一个 n × n 的二维矩阵 matrix 表示一个图像。请你将图像顺时针旋转 90 度。

你必须在 原地 旋转图像,这意味着你需要直接修改输入的二维矩阵。请不要 使用另一个矩阵来旋转图像。

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

解法1:
思路:首先将二维矩阵上下对称交换,然后按照对角线交换

123                789                741
456   对称交换--->  456   对角线交换---> 852  
789                123                963
public static void rotate(int[][] matrix) {
        //调换位置 上下
        for (int i = 0; i < matrix.length / 2; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                int temp = matrix[i][j];
                matrix[i][j] = matrix[matrix.length - 1 - i][j];
                matrix[matrix.length - 1 - i][j] = temp;
            }
        }
        //调换位置 对角线
        for (int i = 0; i < matrix.length; i++) {
            for (int j = 0; j < matrix[0].length; j++) {
                if(i == j)break;
                int temp = matrix[i][j];
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TorlesseLiang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值