LeetCode——数组

目录

    • 一、返回缺失的数字
    • 二.二分查找
    • 三、LinkedList
    • 四、HashTable/Map/Set
    • 五、搜索旋转排序数组(33)mid
    • 五、字符串去重
    • 六、二叉搜索树(700)
    • 七、搜索位置插入(35)
    • 八、外观数列(38)
    • 九、删除排序数组中的重复项(26)
    • 十、多数元素(169)
    • 十一、求众数 II(229)
    • 十二、杨辉三角(118)
    • 十三、数字中重复的数字
    • 十四.有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?
    • 十五、旋转数组的最小数字(二分法 154/10)
    • 十六、打印从 1 到最大的 n 位数(17)
    • 十七、调整数组顺序使奇数位于偶数前面(21)
    • 十八. 数组中的第K个最大元素(215\阿里)
    • 十九、在排序数组中查找数字(34\53)
    • 二十、最大子序和(动归)
    • 二十一:最小的k个数(40)
    • 二十二、返回0-n-1缺失数字(53)
    • 二十三、存在重复元素(217.)
    • 二十四、存在重复元素(219)
    • 二十五、存在重复元素 III(220)

一、返回缺失的数字

如[0,1,3,50,75],返回[2, 4->49, 51->74, 76->99]

package 面试算法;
import java.sql.SQLOutput;
import java.util.ArrayList;
import java.util.List;

public class FindMissnumbers {
     private static List<String>  findmissnumbers (int [] nums ,int lower,int upper){
         // Step1. define return value(需要返回)
         List<String> rst = new ArrayList<>();

         //Step2. handle corner case
         if (nums==null||nums.length==0){
             rst.add(lower+"->"+upper);//无数字,就返回给定区间
             return rst;
         }
         //Step3. Fill in business logic
         //3.1返回lower之后缺少的,如果nums第一个是3   lower是0
           addToList(rst,lower,nums[0]-1);
         //3.2返回lower至upper之间的(数组间)
         int  prev=nums[0];
         int i =1;
         while(i<nums.length){
             int cur=nums[i];
             if (cur!=prev+1){
                 addToList(rst,prev+1,cur-1);
             }
             prev=cur;
             i++;
         }
         //3.3返回upper之前的
            addToList(rst,nums[nums.length-1]+1,upper);
         return rst;
     }
    //将前面散布抽出一个方法
    private static void addToList(List<String> rst,int start,int end){//两种case,if else
           if(start==end){
               rst.add(String.valueOf(start));//Convert integer to string
           }else if(start<end){
               rst.add(start+"->"+end);
           }
    }
    public static void main(String[] args) {
        int [] nums= {0,1,3,50,75};
        int lower=0;
        int upper=99;

        List<String> rst=findmissnumbers(nums,lower,upper);
        System.out.println(rst.toString());

    }
}

二.二分查找

Linear search(O(n)) VS Binary Search(O(logN)
To do binary search, the array must be SORTED!(一定二分查找)
本质:每次搜索范围变1/2
实际开发中,当进行到迭代n时,出现Bug,要求给定迭代,返回是good还是bug。
E.g 1 2 3 4 5 6 7 8 9 10
G G G B B B B B B B

package 面试算法;
public class FirstBadVersion {
    private static int FIRST_BAD=5;
    private static boolean isBadVersion(int version){
        if(version>=FIRST_BAD){
            return true;
        }
        return false;
    }
    private static int firstBadVersion(int n){
        int low =1;
        int high=n;
        while(low<high){
            int middle=low+(high-low)/2;//不写(low+high)/2,避免overflow
            if (isBadVersion(middle)){
                high=middle;
            }else {
                low=middle+1;
            }
        }
        return low;
    }
    public static void main(String[] args) {
        int rst =firstBadVersion(10);
        System.out.println(rst);
    }
}

三、LinkedList

LeetCode——数组_第1张图片
LeetCode——数组_第2张图片
Take-away

use dummy node to simplify  corner cases
oneway,use two pointers

四、HashTable/Map/Set

五、搜索旋转排序数组(33)mid

LeetCode
题目要求 O(logN) 的时间复杂度,基本可以断定本题是需要使用二分查找
LeetCode——数组_第3张图片

class Solution {
    public int search(int[] nums, int target) {
        if (nums == null || nums.length == 0) return -1;
        int start = 0;
        int end = nums.length - 1;       //二分法
        int mid;                 
        while (start <= end) {
            mid = start + (end - start) / 2;
            if (nums[mid] == target) {
                return mid;
            }
            //前半部分有序,注意此处用小于等于
            if (nums[start] <= nums[mid]) {//因为本身就是升序数组
                //target在前半部分
                if (target >= nums[start] && target < nums[mid]) {
                    end = mid - 1;
                } else {
                    start = mid + 1;
                }
            } else {
               if (target <= nums[end] && target > nums[mid]) {
                    start = mid + 1;
                } else {
                    end = mid - 1;
                }
            }

        }
        return -1;
}
}

五、字符串去重

思路:字符串去重,构造一个新的空字符串,遍历老字符串,如果新的字符串中不存在老的字符,添加到新的字符串中。

代码:
	public static String deleteRepeatString(String str) {
		String s = "";
		for(int i = 0; i < str.length(); i++) {
			char c = str.charAt(i);
			if(s.indexOf(c) == -1) {
				s+=c;
			}
		}
		return s;
	}
}

六、二叉搜索树(700)

二叉搜索树是一棵二叉树,每个节点都有以下特性:
大于左子树上任意一个节点的值,
小于右子树上任意一个节点的值。
递归实现非常简单:

如果根节点 root == null 或者根节点的值等于搜索值 val == root.val,返回根节点。
如果 val ,进入根节点的左子树查找 searchBST(root.left, val)。 如果 val > root.val,进入根节点的右子树查searchBST(root.right, val)。

七、搜索位置插入(35)

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

模板

class Solution {
    public int searchInsert(int[] nums, int target) {
        int left = 0, right = nums.length - 1; // 注意
        while(left <= right) { 
            int mid = (left + right) / 2; // 注意
            if(nums[mid] == target) { // 注意
                // 相关逻辑
            } else if(nums[mid] < target) {
                left = mid + 1; // 注意
            } else {
                right = mid - 1; // 注意
            }
        }
        // 相关返回值
        return 0;
    }
}

代码

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

八、外观数列(38)

public static String countAndSay1(int n) {
        StringBuilder s = new StringBuilder();
        int p1 = 0;
        int cur = 1;
        if ( n == 1 )
            return "1";
        String str = countAndSay(n - 1);
        for ( cur = 1; cur < str.length(); cur++ ) {
            if ( str.charAt(p1) != str.charAt(cur) ) {// 如果碰到当前字符与前面紧邻的字符不等则更新此次结果
                int count = cur - p1;
                s.append(count).append(str.charAt(p1));
                p1 = cur;
            }
        }
//        if ( p1 != cur ){// 防止最后一段数相等,如果不等说明p1到cur-1这段字符串是相等的
//            int count = cur - p1;
//            s.append(count).append(str.charAt(p1));
//        }
        s.append(cur-p1).append(str.charAt(p1));
        return s.toString();
    }

九、删除排序数组中的重复项(26)

题解:LeetCode

给定数组 nums = [1,1,2],
函数应该返回新的长度 2, 并且原数组 nums 的前两个元素被修改为 1, 2。

class Solution {
    public int removeDuplicates(int[] nums) {
        if(nums.length==0) return 0;//边界值
        int i=0;                    //慢指针
        for(int j=1;j<nums.length;j++){
            if(nums[i]!=nums[j]){
                i++;
                nums[i]=nums[j];.//往前走
            }
        }
        return i+1;
    }
}

十、多数元素(169)

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

方法一:排序

思路:既然数组中有出现次数> ⌊ n/2 ⌋的元素,那排好序之后的数组中,相同元素总是相邻的。
数组中间的元素总是“多数元素”,毕竟它长度> ⌊ n/2 ⌋

代码:
class Solution {
    public int majorityElement(int[] nums) {
       Arrays.sort(nums);
       return nums[(nums.length)/2];
    }
}

方法二:摩尔投票

算法:候选人(cand_num)初始化为nums[0]票数count初始化为1。 当遇到与cand_num相同的数,则票数 count + 1,否则票数 count - 1。 当票数count为0时,更换候选人,并将票数count重置为1。 遍历完数组后,cand_num即为最终答案

进一步解释:投票法是遇到相同的则票数 + 1,遇到不同的则票数 - 1。 且“多数元素”的个数> ⌊ n/2 ⌋,其余元素的个数总和<= ⌊ n/2
⌋。 因此“多数元素”的个数 - 其余元素的个数总和 的结果 肯定 >= 1。 这就相当于每个“多数元素”和其他元素
两两相互抵消,抵消到最后肯定还剩余至少1个“多数元素”

代码:
class Solution {
    public int majorityElement(int[] nums) {
       int cand=nums[0],count=1;       //初始化一个候选
       for(int i=1;i<nums.length;i++){  //从第二个判断
           if(cand==nums[i]) {          //如果等于,则数量加1
            ++count;
            }else if(--count==0){       //不等,count-1,减到0则换人
            cand=nums[i];
            count=1;
            }
       }
       return cand;
}
}

十一、求众数 II(229)

给定一个大小为 n 的数组,找出其中所有出现超过 ⌊ n/3 ⌋ 次的元素。此题没保证一定存在

说明: 要求算法的时间复杂度为 O(n),空间复杂度为 O(1)。

首先我们得明确,n/k的众数最多只有k-1个,为什么呢?假设有k个众数,n/k *
k=n,这k个元素都是众数,还要不同,怎么可能啊。那么对于这个题,超过n/3的数最多只能有3-1 = 2
个,我们可以先选出两个候选人A,B。 遍历数组,分三种情况:

候选1:> n/3 候选2:> n/3 其他:< n/3

十二、搜索二维矩阵 II(240)

编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target
该矩阵具有以下特性:
每行的元素从左到右升序排列。
每列的元素从上到下升序排列。
[
[1, 4, 7, 11, 15],
[2, 5, 8, 12, 19],
[3, 6, 9, 16, 22],
[10, 13, 14, 17, 24],
[18, 21, 23, 26, 30]
]

思路:从右上角开始和target比较,大于target则去去掉列,小于target去掉行,直至相等

class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
       if(matrix.length==0||matrix[0].length==0){//起始判断
        return false;
        }
        int row=0;
        int col=matrix[0].length-1;      //右上角的元素
        while(col>=0 &&matrix.length>row){
            if(target<matrix[row][col]){   //比列小,去掉列
                col--;
            }else if(target>matrix[row][col]){//比列大,去掉行
                row++;
            }else
            return  true;    
        }
        return false;
    }
}

十二、杨辉三角(118)

十三、数字中重复的数字

在一个长度为 n 的数组 nums 里的所有数字都在 0~n-1
的范围内。数组中某些数字是重复的,但不知道有几个数字重复了,也不知道每个数字重复了几次。请找出数组中任意一个重复的数字。

class Solution {
    public int findRepeatNumber(int[] nums) {
       Set<Integer> set = new HashSet<Integer>();
       int repeat=-1;
       for(int num: nums){
           if(!set.add(num)){
               repeat=num;
               break;
           }
       }
       return repeat;
    }
}

十四.有1、2、3、4个数字,能组成多少个互不相同且无重复数字的三位数?都是多少?

代码:但是如果是 0 1 2 3 
public class LianXi {
    public static void main(String[] args) {
        //创建一个长度为4的数组
        int[] arr = new int[4];
        Scanner input = new Scanner(System.in);
        //循环将用户的输入的数据放入数组中
        for (int i = 0; i < arr.length; i++) {
            System.out.println("输入第" + (i + 1) + "个数");
            arr[i] = input.nextInt();
        }
        //依次将数组中的所有数都遍历出来
        for (int j = 0; j < arr.length; j++) {
            for (int j2 = 0; j2 < arr.length; j2++) {
                for (int k = 0; k < arr.length; k++) {
                    //判断遍历后的数是否有重复的数字,剔除所有重复的数字之后打印出来
                    if (arr[j] != arr[j2] && arr[j] != arr[k] && arr[j2] != arr[k]) {
                        System.out.print((arr[j] * 100 + arr[j2] * 10 + arr[k]) + " ");
                    }
                }
            }
            System.out.println();
        }
    }
}

十五、旋转数组的最小数字(二分法 154/10)

把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。例如,数组[3,4,5,1,2] 为 [1,2,3,4,5] 的一个旋转,该数组的最小值为1。

常规解法:出现后面数字比前面数字小,返回,如没有,返回第一个

class Solution {
    public int minArray(int[] numbers) {
        for(int i=0; i<numbers.length-1;i++){
            if(numbers[i]>numbers[i+1])
             return numbers[i+1];
        }
             return numbers[0]; }
}

思路:关键找到右边最小的

排序数组的查找问题首先考虑使用 二分法 解决,其可将遍历法的 线性级别 时间复杂度降低至 对数级别 。

class Solution {
    public int findMin(int[] nums) {
        int left=0,right=nums.length-1;     //左右指针
        while(left<right){                  //终止条件
            int mid=(left+right)/2;         //中间值
            if(nums[mid]>nums[right]){      //中间>右大,那么目标值在右侧【mid+1,right】
            left=mid+1;
            }else if(nums[mid]<nums[right]){
            right=mid;                      //最小值在左侧
            }else right--;                 //保证重复时候
           }   
        return nums[left];
    }
}

十六、打印从 1 到最大的 n 位数(17)

例如3、打印1、2、3、…999
思路:9、99、999.其实就是打印[1-10^n-1]

class Solution {
    public int[] printNumbers(int n) {
        int end= (int)Math.pow(10,n)-1;//默认不超过int
        int[]arr=new int[end];
        for(int i= 0;i <end; i++) {
            arr[i]=i+1;
        }
        return arr;
    }
}

十七、调整数组顺序使奇数位于偶数前面(21)

例如:【1.23.4】——[3,1,2,4]
思路:双指针碰撞[leetcode]

class Solution {
    public int[] exchange(int[] nums) {
        int i = 0, j = nums.length - 1, tmp;
        while(i < j) {
            while(i < j && (nums[i]%2==1))i++;
            while(i < j && (nums[j]%2==0)) j--;
            tmp = nums[i];
            nums[i] = nums[j];
            nums[j] = tmp;
        }
        return nums;
    }
}

十八. 数组中的第K个最大元素(215\阿里)

在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。

思路:leetcode
方法一;时间复杂度为 O(NlogN),空间复杂度为O(1)

class Solution {
    public int findKthLargest(int[] nums, int k) {
        int i =nums.length;
        Arrays.sort(nums);
        return nums[i-k]; }
}

方法二:基于快排

十九、在排序数组中查找数字(34\53)

我写的没看到排序数组两个字
class Solution {
    public int search(int[] nums, int target) {
        int count = 0;
        for(int i = 0; i < nums.length; i++ ){
            if(nums[i]==target){
                count++; }
        }
        return count;
    }
}

二分法解决排序数组

class Solution {
    public int search(int[] nums, int target) {
        return helper(nums, target) - helper(nums, target - 1);
    }
    int helper(int[] nums, int tar) {
        int i = 0, j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] <= tar) i = m + 1;
            else j = m - 1;
        }
        return i;
    }
}

二十、最大子序和(动归)

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
示例:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
leetcode

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

二十一:最小的k个数(40)

题目:[1,2,3,4] k=2 结果[1,2][2,1]

class Solution {
    public int[] getLeastNumbers(int[] arr, int k) {
        Arrays.sort(arr);
        int [] nums=new int [k];
        for(int i =0; i<k ;i++){
           nums[i]= arr[i];
        }
        return nums;
    }
}

二十二、返回0-n-1缺失数字(53)

二分法:
时间复杂度 O(logN): 二分法为对数级别复杂度。
空间复杂度 O(1): 几个变量使用常数大小的额外空间。

class Solution {
    public int missingNumber(int[] nums) {
        int i = 0, j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] == m) i = m + 1;
            else j = m - 1;
        }
        return i;
    }
}

遍历:
只要比较数组下标和该下标对应的值即可,再排除缺失0和缺失最后一项两个特殊情况。

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

二十三、存在重复元素(217.)

如果数组中有重复数字,返回true

自己想的 时间空间O(n)
class Solution {
    public boolean containsDuplicate(int[] nums) {
        HashSet<Integer> set = new HashSet<>();
            for(int i=0;i<nums.length;i++){
                set.add(nums[i]);
            }
            return !(nums.length==set.size());
   }
}
public boolean containsDuplicate(int[] nums) {
    Set<Integer> set = new HashSet<>(nums.length);
    for (int x: nums) {
        if (set.contains(x)) return true;
        set.add(x);
    }
    return false;
}

二十四、存在重复元素(219)

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

public class Solution219 {
    public static boolean containsNearbyDuplicate(int [] nums, int k){
        HashSet<Integer> set = new HashSet<>();
        for (int i = 0; i <nums.length ; i++) {
            if(set.contains(nums[i])){        //包含一个,返回true
                return true;
            }
            set.add(nums[i]);              //没有,添加进去
            if(set.size()>k){               //这个哈希表长度为k
                set.remove(nums[i-k]);
            }
        }
        return false;
    }

二十五、存在重复元素 III(220)

Leetcode

在整数数组 nums 中,是否存在两个下标 i 和 j,使得 nums [i] 和 nums [j] 的差的绝对值小于等于 t ,且满足 i 和 j 的差的绝对值也小于等于 ķ 。
LeetCode——数组_第4张图片
解法一:

public boolean containsNearbyAlmostDuplicate(int[] nums, int k, int t) {
    for (int i = 0; i < nums.length; ++i) {
        for (int j = Math.max(i - k, 0); j < i; ++j) {
            if (Math.abs(nums[i] - nums[j]) <= t) return true;
        }
    }
    return false;
}
// Time limit exceeded.

你可能感兴趣的:(算法代码)