Leetcode 数组 Easy Java 11道

安卓开发及安全交流QQ群:838650234,感兴趣的可以加群。

以后就征战Leetcode啦,相比于杭电OJ,Leetcode面向工作,每道题都有思考的余地,对比别人的代码很容易发现自己代码的不足,时间复杂度、代码的可读性、规范等等都会给我们一些启示。这是杭电OJ所没有的,废话不多说,开始啦!

(一)26题 删除排序数组中的重复项

题目大致内容:

给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。不要使用额外的数组空间,你必须在原地修改输入数组并在使用 O(1) 额外空间的条件下完成。

具体题目链接:

https://leetcode-cn.com/problems/remove-duplicates-from-sorted-array/description/

解题思路:

(1)反向遍历一维数组,若后者与前者相等,则置后者的值为Flag(这里的Flag取数组的第一个元素-1);可以统计出移除后新数组的长度。

(2)随后执行交换操作,具体是将不等于Flag的数放在前面,将该处位置内容置成Flag即可。同时需要考虑数组元素为null的情况。

具体代码:

 public static int removeDuplicates(int[] nums) {
        //注意数组元素为零的情况。
        if (nums.length != 0) {
            int flag = nums[0] - 1;
            int all_length = nums.length;
            //将重复元素都设置成比第一个元素小的数。然后对其统计数据进行--操作。
            for (int i = nums.length - 1; i > 0; i--) {
                //反向计算会效果好一些。
                if (nums[i] == nums[i - 1]) {
                    nums[i] = flag;
                    all_length--;
                }
            }
            //进行元素的移动操作
            for (int i = 0; i < nums.length; i++) {
                if (nums[i] == flag) {
                    for (int j = i; j < nums.length; j++) {
                        if (nums[j] != flag) {
                            nums[i] = nums[j];
                            nums[j] = flag;
                            break;
                        }
                    }
                }
            }
            return all_length;
        } else {
            return 0;
        }
    }

*(二)122题  买卖股票的最佳时机 II

题目大致内容:

给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

具体题目链接:

https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/description/

解题思路:

       第一遍并没有很理解这个题,看了别人的代码后发现好简单。完全可以当天买当天卖的,可以用贪心法求解,策略:反向遍历,只要后一天的股票价格比前一天高,就在前一天买入,后一天卖出;反之什么也不做。

具体代码:

   public static int maxProfit(int[] prices) {
        int maxprofit  = 0;
        for (int j = prices.length - 1; j > 0; j--) {
            if(prices[j] >prices[j-1]){
                maxprofit +=(prices[j] - prices[j-1]);
            }
        }
        return maxprofit;
    }

(三)189. 旋转数组

题目大致内容:

给定一个数组,将数组中的元素向右移动 个位置,其中 是非负数。

具体题目链接:

https://leetcode-cn.com/problems/rotate-array/description/

解题思路:

      如果数组为null,则return,否则对于该数组的最后一个元素,将其赋给数组的第一个元素,对于其他元素,数组中后者的值等于前者的值,向右移动k个位置,利用while循环执行k次即可。

具体代码:

 public static void rotate(int[] nums, int k) {
        if(nums.length == 0){return;}
        int count = 0;
        int tmp = 0;
        //1.每次记录的是最后一个数字,将其赋值给一个变量,然后将前者的值赋给后者。
        while (count < k) {
            tmp = nums[nums.length - 1];
            for (int i = nums.length - 1; i > 0; i--) {
                nums[i] = nums[i - 1];
            }
            nums[0] = tmp;
            count++;
        }
    }

(四)217. 存在重复元素

题目大致内容:

给定一个整数数组,判断是否存在重复元素。如果任何值在数组中出现至少两次,函数返回 true。如果数组中每个元素都不相同,则返回 false。

具体题目链接:

https://leetcode-cn.com/problems/contains-duplicate/description/

解题思路(一):

      刚开始觉得较为简单,双重循环进行遍历,若相等,则return false。发现时间复杂度太高,哪能让你轻易这么过哦,哈哈哈....然后尝试使用Hashset去解决,相比于ArrayList、LinkList。HashSet天生就是为了提高查找效率的。具体可以查看HashSet的结构:https://www.cnblogs.com/runwulingsheng/p/5208762.html。那么然后就简单了,一遍过。若该HahsSet中不存在该元素,则add进去,若存在,则return。

解题思路(二):

      先利用Arrays数组进行排序,然后数组中的前者和后者进行对比,得出结果。Arrays.sort()使用了归并排序算法,时间复杂度为O(nlogn),好像也没有超时。

具体代码:

public static boolean containsDuplicate(int[] nums) {
        if(nums.length == 0||nums.length==1) return false;
        //1.对于数组元素进行遍历,若有相等,则return true,否则false,越界的判断一定要确定。但时间复杂度太高。
//        for(int i = 0 ;i<nums.length-1;i++){
//            for(int j = i+1;j<nums.length;j++){
//                if(nums[i] == nums[j]){
//                    return true;
//                }
//            }
//        }
        //2.ArrayList、LinkList效率低的可怕。HashSet天生就是为了提高查找效率的。HashSetadd时若想等会新数据将被视为已经加入,而不再重复丢入链表。
        HashSet<Integer> hashSet_01 = new HashSet<Integer>();
        for(int i = 0 ;i<nums.length;i++){
            if(hashSet_01.contains(nums[i])){
                return true;
            }else{
                hashSet_01.add(nums[i]);
            }
        }
        //3.先利用Arrays数组进行排序,然后对前者和后者进行对比,得出结果。
//        Arrays.sort(nums);
//        for(int i = 0 ;i<nums.length;i++){
//            if(nums[i+1] == nums[i]){
//                return true;
//            }else{
//                return false;
//            }
//        }
        return false;
    }

(五)136. 只出现一次的数字

题目大致内容:

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?。

具体题目链接:

https://leetcode-cn.com/problems/single-number/description/

解题思路(一):

      利用HashSet进行存储,如果HashSet不包含,则add这个元素进去,否则remove掉这个元素,最后HashSet剩下一个元素利用.iterator().next();来逐个获取内容元素。

解题思路(二):

      看了大佬的做法,瞬间觉得自己low到爆,遍历一遍数组,每个相邻元素之间进行异或操作,这个时候不论两个元素有多远都会进行异或,异或之后结果为零,剩余的元素就为出现了一次的元素。

具体代码:

 public static int singleNumber(int[] nums) {
        //1.利用HashSet进行存储,然后用.iterator().next();来逐个获取内容元素
        if (nums.length == 1) return nums[0];
        HashSet<Integer> hashSet_01 = new HashSet<Integer>();
        for (int i = 0; i < nums.length; i++) {
            if (hashSet_01.contains(nums[i])) {
                hashSet_01.remove(nums[i]);
            } else {
                hashSet_01.add(nums[i]);
            }
        }
        //获取Hahset容器中的第一个元素。啦啦啦好开心,通过啦。
        return hashSet_01.iterator().next();

        //用异或完美解决
//        if (A == null || A.length == 0) {
//            return -1;
//        }
//        int rst = 0;
//        for (int aA : A) {
//            rst ^= aA;
//        }
//        return rst;
    }

(六)350. 两个数组的交集 II

题目大致内容:

给定两个数组,编写一个函数来计算它们的交集。
说明:输出结果中每个元素出现的次数,应与元素在两个数组中出现的次数一致。我们可以不考虑输出结果的顺序。

具体题目链接:

https://leetcode-cn.com/problems/intersection-of-two-arrays-ii/description/

启发:1.没有什么高大上的代码;2.不要惧怕问题方法的复杂度,只要能解决问题的方法就是好方法。

解题思路(一):

      利用两个动态数组进行解决,(1)将数组二赋值给动态数组一。(2)遍历数组一,若动态数组一包含该数组一内的元素,则remove掉该元素,并将该元素add进动态数组二中。(3)最后将动态数组二赋值给一个数组,return回去。

解题思路(二):

      别人的做法,利用Arrays的sort的API,进行下标递加操作。操作较为简单,再return.。

具体代码:

public static int[] intersect(int[] nums1, int[] nums2) {
        ArrayList<Integer> arrayList_01 = new ArrayList<Integer>();
        ArrayList<Integer> arrayList_02 = new ArrayList<Integer>();
        //1.将第二个数组内的元素存储进动态数组里
        for (int i = 0; i < nums2.length; i++) {
            arrayList_01.add(nums2[i]);
        }
        //2.若包含,则添加元素进新数组,删除旧数组中的元素。
        for (int i = 0; i < nums1.length; i++) {
            if (arrayList_01.contains(nums1[i])) {
                arrayList_02.add(nums1[i]);
                arrayList_01.remove(arrayList_01.indexOf(nums1[i]));
            }
        }
        //3.动态数组对数组的一个赋值。
        int []result = new int[arrayList_02.size()];
        for(int j = 0 ;j<arrayList_02.size();j++){
            result[j] = arrayList_02.get(j);
        }
        return result;
    }
    //2.利用Arrays的sort方法结合若相等,则下标递加操作。计算出其总共有多大,再return.
//    public int[] intersect(int[] nums1, int[] nums2) {
//        if (nums1 == null || nums2 == null) return null;
//        Arrays.sort(nums1);
//        Arrays.sort(nums2);
//    int N = nums1.length;
//    int M = nums2.length;
//    int L = Math.min(M, N);
//    int[] temp = new int[L];
//    int i = 0;
//    int j = 0;
//    int k = 0;
//        while (i < N && j < M ) {
//        if (nums1[i] < nums2[j]) i++;
//        else if (nums1[i] > nums2[j]) j++;
//        else {
//            temp[k++] = nums1[i];
//            i++;
//            j++;
//        }
//    }
//    int[] result = new int[k];
//        for (int r = 0; r < k; r++) {
//        result[r] = temp[r];
//    }
//        return result;
//}

(七)66. 加一

题目大致内容:

给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一。
最高位数字存放在数组的首位, 数组中每个元素只存储一个数字。
你可以假设除了整数 0 之外,这个整数不会以零开头。

具体题目链接:

https://leetcode-cn.com/problems/plus-one/description/

解题思路:

      刚开始尝试拼接数组内元素成字符串然后转成Long类型的方法,发现转成之后超过Long的范围,故而采用了:反向遍历该数组内的元素:1.若当前位元素为9,则置零;2.若当前位元素小于9,则加一;3.若当前位元素为9且为当前位最高位时,再建一个数组,其长度为之前数组的长度加一,将其首位置1即可。

具体代码:

public static int[] plusOne(int[] digits) {
        //如果最后一位小于9,则不用进位。
        boolean flag = false;
        for (int i = digits.length - 1; i >= 0; i--) {
            //1.若当前位为9,则置零;2.若当前为小于9,则加一;3.若当前位为9且为最高位时,则执行置零设置标志位操作。
            if (digits[i] == 9 && i != 0) {
                digits[i] = 0;
            } else if (digits[i] == 9 && i == 0) {
                digits[i] = 0;
                flag = true;
            } else {
                digits[i] += 1;
                break;
            }
        }
        if (!flag) {
            return digits;
        }else{
            int []result = new int[digits.length+1];
            result[0] = 1;
            return result;
        }
    }

(八)283. 移动零

题目大致内容:

给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
说明:
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。

具体题目链接:

https://leetcode-cn.com/problems/move-zeroes/description/

解题思路(一):

      进行双重循环遍历,分为三种情况,(1)若当前两个数组元素下标相等且数组内容不等于零,则下一个;(2)若当前两个数组元素下标不等且数组内容等于零。若找到数组内容不为零的则将其赋值,并将该位置的元素内容置零。

解题思路(二):

      设置start和index两个标识。若相等,当前位置++,若不等,则检查为标识++。将当前后面所有位置零。

具体代码:

 //1.进行遍历,分为三种情况,(1)若当前两个相等,则下一个;(2)若当前两个不等,则往下去找有没有相等的。若找到则赋值,并将该位置零。
    public static void moveZeroes(int[] nums) {
        for (int i = 0; i < nums.length; i++) {
            for (int j = i; j < nums.length; j++) {
                if (nums[j] != 0 && j != i) {
                    nums[i] = nums[j];
                    nums[j] = 0;
                    break;
                } else if (nums[j] != 0 && j == i) {
                    break;
                }
            }
        }
        return;
    }
    //2.代码更为凝练,设置start和index两个标识。若相等,当前位置++,若不等,则检查为标识++。将当前后面所有位置零。
//    public void moveZeroes(int[] nums) {
//        int start = 0;
//        int index = 0;
//        int length = nums.length;
//        while(index < length){
//            if(nums[index] != 0){
//                nums[start] = nums[index];
//                start++;
//            }
//            index++;
//        }
//        while(start < length){
//            nums[start] = 0;
//            start++;
//        }
//    }

(九)1. 两数之和

题目大致内容:

给定一个整数数组和一个目标值,找出数组中和为目标值的两个数。你可以假设每个输入只对应一种答案,且同样的元素不能被重复利用。

具体题目链接:

https://leetcode-cn.com/problems/two-sum/description/

解题思路:

      双重循环,若两数之和则利用一个数组长度为2的数组存其当前两个位置的下标,可能因为是第一个吧,所以较为简单。

具体代码:

//1.进行双重循环的判断即可。
    public static int[] twoSum(int[] nums, int target) {

        for(int i = 0;i<nums.length-1;i++){
            for(int j = i+1;j<nums.length;j++){
                if(nums[i]+nums[j] == target){
                    int []result = {i,j};
                }
            }
        }
        return null;
    }

(十)1. 两数之和

题目大致内容:

具体题目链接:

https://leetcode-cn.com/problems/valid-sudoku/description/

解题思路:

      问题较为直接,故而解决方法也较为粗暴,(1)双重循环判断每一行符合数独的条件,若不满足则return flase。(2)双重循环判断每一列符合数独的条件,若不满足则return flase。(3)判断每个 3x3 宫内是否符合数独的条件,一共九个,将其存成长度为9的一维数组(吐槽一句:计算下标真麻烦啊····),然后进行判断。只有符合这个条件的才会return true。

具体代码:

 public static boolean isValidSudoku(char[][] board) {

        //1.判断每一行符合数独的条件么。
        for (int k = 0; k < 9; k++) {
            for (int i = 0; i < 8; i++) {
                for (int j = i + 1; j < 9; j++) {
                    if (board[k][i] == board[k][j] && board[k][i] != '.') {
                        return false;
                    }
                }
            }
        }
        //2.判断每一列符合数独的条件。
        for (int k = 0; k < 9; k++) {
            for (int i = 0; i < 8; i++) {
                for (int j = i + 1; j < 9; j++) {
                    if (board[i][k] == board[j][k] && board[i][k] != '.') {
                        return false;
                    }
                }
            }
        }

        //3.判断每个 3x3 宫内是否符合数独的条件
        for (int k = 0; k < 9; k++) {
            int[] test_33 = new int[9];
            int m = 0;
            //进行赋值操作,每九个存放到一个数组里面
            if (k < 3) {
                for (int i = 0; i < 3; i++) {
                    for (int j = 3 * k + 0; j < 3 * k + 3; j++) {
                        test_33[m] = board[i][j];
                        m++;
                    }
                }
            } else if (k >= 3 && k < 6) {
                for (int i = 3; i < 6; i++) {
                    for (int j = 3 * (k - 3) + 0; j < 3 * (k - 3) + 3; j++) {
                        test_33[m] = board[i][j];
                        m++;
                    }
                }
            }else{
                for (int i = 6; i < 9; i++) {
                    for (int j = 3 * (k - 6) + 0; j < 3 * (k - 6) + 3; j++) {
                        test_33[m] = board[i][j];
                        m++;
                    }
                }
            }
            //进行判断
            for (int i = 0; i < 8; i++) {
                for (int j = i + 1; j < 9; j++) {
                    if (test_33[i] == test_33[j] && test_33[i] != '.') {
                        return false;
                    }
                }
            }
        }
        return true;
    }

(十一·)1. 两数之和

题目大致内容:

具体题目链接:

https://leetcode-cn.com/problems/rotate-image/description/

解题思路:

      第一步:每一行变为每一列,第二步:当前矩阵中的每一行中元素的每一列进行反向赋值。最终实现旋转90度。

具体代码:

public static void rotate(int[][] matrix) {
        int flag = 0;
        int length = matrix.length;
        //调换对角元素。
        for (int i = flag; i < length; i++) {  //行
            for (int j = flag; j < length; j++) {  //列
                if (i != j && matrix[i][j] != matrix[j][i]) {
                    int tmp = matrix[j][i];
                    matrix[j][i] = matrix[i][j];
                    matrix[i][j] = tmp;
                }
            }
            flag++;
        }
        //调换每行元素。
        for (int i = 0; i < length; i++) {  //行
            for (int j = 0; j < length/2; j++) {  //列
                if (matrix[i][j] != matrix[i][length - 1 - j]) {
                    int tmp = matrix[i][j];
                    matrix[i][j] = matrix[i][length - 1 - j];
                    matrix[i][length - 1 - j] = tmp;
                }
            }
        }
        return;
    }

猜你喜欢

转载自blog.csdn.net/weixin_38244174/article/details/82629329