小彩笔的刷题痛苦之旅 —— 数组(入门、简单)

题目与解题思路均来自牛客网

入门:

  第一题:求斐波那契数列的第n项

public static int fibD(int n){ //递归方法
        if(n == 1 || n == 2){
            return 1;
        }
        else{
            return fibD(n-1) + fibD(n - 2);
        }
    }
    public static int fibX(int n){ //循环方法
        if(n < 0){
            return -1;
        }
        int f1 = 1;
        int f2 = 1;
        int f3 = 1;
        for (int i = 2; i < n; i++) {
            f3 = f1 + f2;
            f1 = f2;
            f2 = f3;
        }
        return f3;
    }

    public static void main(String[] args) {
        System.out.println(fibD(10));
        System.out.println(fibX(10));
    }

总结:

  • 建议使用循环方式,因为递归方式计算时间会很久。

  第二题:给定一个m × n大小的矩阵(m行, n列),按螺旋的顺序返回矩阵中的所有元素。

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

&ems; 主要是找出螺旋的规律,和边界的判别。

  • 1、如果数字为空,则返回空数组
  • 2、定义四个边界以及当前方向
  • 3、当左边界小于等于右边界,且上边界小于等于下边界时,执行while循环:按照 左→右,上→下,右→左,下→上的顺序,依次将路径上的字符添加到结果里。
public static ArrayList<Integer> spiralOrders1(int[][] matrix) {
        ArrayList<Integer> res = new ArrayList<Integer>();
        if(matrix.length==0)
            return res;
        if(matrix[0].length==0)
            return res;
        int up = 0;
        int down = matrix.length-1;
        int left = 0;
        int right = matrix[0].length-1;
        int i=0;
        while(true){
            if(left>right){
                return res;
            }
            //向右
            for(int k=left;k<=right;k++)
                res.add(matrix[up][k]);
            up++;
            if(up>down){
                return res;
            }
            //向下
            for(int k=up;k<=down;k++)
                res.add(matrix[k][right]);
            right--;
            if(left>right){
                return res;
            }
            //向左
            for(int k=right;k>=left;k--)
                res.add(matrix[down][k]);
            down--;
            if(up>down) {
                return res;
            }
            //向上
            for(int k=down;k>=up;k--)
                res.add(matrix[k][left]);
            left++;
        }
    }
    public static void main(String[] args) {
        ArrayList<Integer> n = new ArrayList<Integer>();
        int[][] matrix = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};
        System.out.println(spiralOrders1(matrix));
    }

  第三题:山峰元素是指其值大于等于左右相邻的元素。给定一个输入数组nums,任意两个相邻元素值不相等,数组可能包含多个山峰。找到索引最大的那个山峰元素并返回其索引。

输入:[2,4,1,2,7,8,4]
输出:5
    public static int solve (int[] a) {
        // write code here
        int index=0;
        for(int i=1;i<a.length;i++){
            if(a[i-1]<a[i]){
                index=i;
            }
        }
        return index;
    }
    public static void main(String[] args) {
        int[] b = {1,2,4,5,3,7,9,11,2,33,43,9};
        int m = solve(b);
        System.out.println(m);
    }
  • 总结:通过循环寻找峰值,即前一个值小于后一个值就是山峰。通过判断数组前一个值是否小于后一个值,如果是,则将下标值i赋给index,不断更新寻找。

  第四题:给定一个整型矩阵matrix,请按照顺时针转圈的方式打印它。

    //转圈打印矩阵
    public static ArrayList<Integer> rotationMatrix(int[][] matrix){
        //第一步:new一个新的数组对象
        ArrayList<Integer> rec = new ArrayList<Integer>();
        //第二步:判空
        if(matrix.length == 0){
            return rec;
        }
        if(matrix[0].length == 0){
            return rec;
        }
        //第三步:定义边界
        int top = 0;
        int bottom = matrix.length - 1;
        int left = 0;
        int right = matrix[0].length - 1;

        //第四步:循环赋值
        while(true){
            //进行边界判别,//从左到右
            if(left > right){
                return rec;
            }
            for (int i = left; i <= right; i++) {
                rec.add(matrix[top][i]);
            }
            top++;
            //判断边界,//从上到下
            if(top > bottom){
                return rec;
            }
            for(int i = top; i <= bottom; i++){
                rec.add(matrix[i][right]);
            }
            right--;
            //判断边界,//从右到左
            if(right < left){
                return rec;
            }
            for (int i = right; i >= left ; i--) { //从右往左
                rec.add(matrix[bottom][i]);
            }
            bottom--;
            //判断边界,//从下到上
            if(bottom < top){
                return rec;
            }
            for (int i = bottom; i >= top; i--) { //从下往上   都要用 --
                rec.add(matrix[i][left]);
            }
            left++;
        }

    }
    public static void main(String[] args){
        int[][] matrix = {{1,2,3,4,5}, {6,7,8,9,10}, {11,12,13,14,15}, {16,17,18,19,20}};
        System.out.println(rotationMatrix(matrix));
    }
  • 总结:
  • 此题思路与第二题思路完全相同,需要注意的的是循环条件与边界条件的选取,当从右往左时循环条件应为right > left且索引为i--,从下往上时循环条件为bottom > top索引也为i--.
    *ArrayList<Integer> rec = new ArrayList<Integer>()此条语句为建立一个新的空数组对象,对象名为rec



简单:

  第一题:给出两个有序的整数数组A和B,请将数组B合并到数组A中,变成一个有序的数组。

  • 假设A和B中初始的元素数目分别为m和n,A数组有足够的空间存放B元素,即空间大小大于或等于m+n。
输入:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6],       n = 3
输出:[1,2,2,3,5,6]
  • 思路一:排序,将第二个数组直接添加到第一个数组后边然后遍历。
public static int[] concet(int[] arr1, int[] arr2, int m, int n){
        int j = 0;
        for (int i = m; i < m+n; i++) {
            arr1[i] = arr2[j];
            j++;
        }
        Arrays.sort(arr1);
        return arr2;
    }
    public static void main(String[] args){
        int[] arr1 = {1,2,3,0,0,0};
        int m = 3;
        int[] arr2 = {2,5,8};
        int n = 3;
        int[] output = concet(arr1,arr2,3,3);
        System.out.println(Arrays.toString(output));
    }
  • 思路二:定义一个额外的数组来保存arr1于arr2比较后的结果,此数组的长度为arr1.length + arr2.length。当arr1的元素小于arr2的元素时,将arr1的元素保存到新建的数组中,同时让arr1和新建的数组下标同时向后移动(++),此时arr2的下标并未发生变化,再次进行比较。
//思路二:额外数组
    public static void concet(int[] arr1, int[] arr2, int m, int n){
        int j = 0;//第一个数组的指针
        int k = 0;//第二个数组的指针
        int[] nums = new int[m+n];
        for (int i = 0; i < nums.length; i++) {
            //防止越界
            if (j < arr1.length && k < arr2.length) {
                if (arr1[j] <= arr2[k]) {
                    nums[i] = arr1[j];
                    j++;
                } else if (arr1[j] > arr2[k]) {
                    nums[i] = arr2[k];
                    k++;
                }
            }
            //如果一个数组比较完了,即k或j大于数组长度时,直接将另一个数组剩下的元素赋给新数组剩余的空间。
            else if(j >= arr1.length){
                nums[i] = arr2[k];
                k++;
                j++;
            }
            else{
                nums[i] = arr1[j];
                j++;
                k++;
            }
        }
        for (int num: nums) {
            System.out.println(num + " ");
        }
    }
    public static void main(String[] args){
        int[] arr1 = {1,2,3,4,5,6};
        int m = 3;
        int[] arr2 = {2,5,8};
        int n = 3;
        concet(arr1,arr2,3,3);
    }
  • 思路三:第二种思路是前插法,但需要开辟新空间,但如果想不额外开辟空间的话,使用前插法在原数组上进行处理会影响到原数组中未处理的值。所以我们使用尾插法(后入?),通过比较最大值,将两者的最大值插入到数组A的末尾。
//思路三:尾插法
    public static void concet(int[] arr1,int[] arr2, int m, int n){
        //m表示arr1元素的长度
        //n表示arr2元素的长度
        for (int i = arr1.length - 1; i >0 ; i--) {
            if(m == 0){ //当arr1中的元素个数为0时,将arr2中的元素从末尾依次插入新数组(arr1数组的额外空间)
                arr1[i] = arr2[n-1];
                n--;
            }
            else if(n == 0){ //当arr2中的元素个数为0时,跳出循环。
                break;
            }
            else if(arr1[m-1] > arr2[n-1]){ //判断两数组给自末尾元素的大小,将更大的元素插入arr1数组的末尾。
                arr1[i] = arr1[m-1];
                m--;
            }
            else{
                arr1[i] = arr2[n-1];
                n--;
            }
        }
        for (int num: arr1) {
            System.out.println(num + " ");
        }
    }
    public static void main(String[] args){
        int[] arr1 = {1,2,3,0,0,0};
        int m = 3;
        int[] arr2 = {2,5,8};
        int n = 3;
        concet(arr1,arr2,3,3);
    }

  第二题:数组中两数之和,给出一个整数数组,请在数组中找出两个加起来等于目标值的数,你给出的函数twoSum需返回这两个数字的下标(index1, index2),需要满足index1小于index2。注意:下标从1开始的。假设给出的数组中子存在唯一解。

输入:[3,2,4], 6
输出:[2,3]
  • 解法一:通过两个循环嵌套来遍历所有结果,将目标结果下标返回。
public static int[] fun(int[] array, int target){
        int[] ret = new int[2];
        for (int i = 0; i < array.length; i++) {
            for (int j = i + 1; j < array.length; j++) {
                if(array[i] + array[j] == target){
                    ret[0] = i;
                    ret[1] = j;
                }
            }
        }
        return ret;
    }
    public static void main(String[] args){
        int[] array = {1,2,3,4,5,6};
        int target = 9;
        int[] output = fun(array, target);
        System.out.println(Arrays.toString(output));
    }

  第三题:数组中相加和为0的三元组。给出一个有n个元素的数组S,S中是否有元素a,b,c满足 a+b+c=0? 找出数组S中所有满足条件的三元组。

  • 注意:
  • 1、三元组(a,b,c)中的元素必须按非降序排列。(即 a ≤ b ≤ c)
  • 2、解集中不能包含重复的三元组
输入:[-2, 0, 1, 1, 2];
输出:[[-2, 0, 2], [-2, 1, 1]]
public static void main(String[] args){
        int[] num = {-2, 0, 1, 1, 2};
        System.out.println(threeSum(num));
    }
    public static ArrayList<ArrayList<Integer>> threeSum(int[] num){
        ArrayList<ArrayList<Integer>> result = new ArrayList<>();
        if (num == null){
            return result;
        }
        //对数组进行排序
        Arrays.sort(num);
        int sum,left,right;

        for (int i = 0; i < num.length - 2; i++) { //因为要找出三个数,所以i只用最多固定到倒数第三个数即可

            //避免重复,例如如果前面已经计算了以-1开头的,后面就不用计算了
            if(i != 0 && num[i] == num[i - 1]){
                continue;
            }
            left = i + 1;
            right = num.length - 1;

            /**
             * 固定一个数,从后面的数中选出两个数,因为数组是有序的,所以可以
             * 用两个数组下标left和right,left指向当前元素的后一个位置,right指向最后一个位置
             * 三个数相加的和等于0时,加入解集
             * 小于0时,把left往右边移动
             * 大于0时,把right往左移动
             */
            while(left < right){
                sum = num[left] + num[right];
                if(sum + num[i] == 0){  //如果三个数等于零,则新建一个数组用来存放这三个数
                    ArrayList<Integer> solution = new ArrayList<>();
                    solution.add(num[i]);
                    solution.add(num[left]);
                    solution.add(num[right]);
                    result.add(solution);
                    left++;
                    right--;
                    //这个优化必须加,不加时间超限,其实这个优化也没太大作用嘛
                    while (left < right && num[left] == num[left - 1]) {
                        left++;
                    }
                    while (left < right && num[right] == num[right + 1]) {
                        right--;
                    }
                } else if (sum + num[i] < 0) {
                    left++;
                } else {
                    right--;
                }
            }

        }
        return result;
    }

  第四题:缺失数字,从0,1,2,…,n这n+1个数,组成有序数列,找出这n个数中缺失的那个数。

输入:[0,1,2,3,4,5,7]
输出:6
  • 拙略的for循环,虽然可以解题,但明显不是最佳解
public static void main(String[] args){
        int[] array = {3,4,5,6,7,9,10};
        int[] array1 = {18,19,20,22,23,24,25};
        int output = findNumber(array1);
        System.out.println(output);
    }
    public static int findNumber(int[] array){
        int j = array[0];
        for (int i = 0; i < array.length; i++) {
            if(array[i] != j){
                return j;
            }
            j++;
        }
        return -1;
    }

  第五题:寻找数组中未出现的最小正

public static int findMinNumber(int[] array){
        if (array.length == 0){
            return 1;
        }
        Arrays.sort(array);
        int len = array.length;
        if(array[len-1] < 0){
            return 1;
        }
        int min = 1;
        for (int i = 0; i < len; i++) {
            if(min == array[i]){
                min++;
            }
        }
        return min;

    }
    public static void main(String[] args){
        int[] array = {-1,-4,-7,3,7,9,4,1,2,6,8,9,45,34,23,-10};
        System.out.println(findMinNumber(array));
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值