算法题-数组算法题

题一:二分查找法-Java:用于有序数组

//实验数据
int[] arr = {3,21,34,46,55,71,74,80,97};

 代码:

public int findIndex(int value, int[] arr) {
        // arr是有序数组
        // value是目标值
        int min = 0; //最大值,最小值的索引值
        int max = arr.length - 1;
        int mid = (min + max) / 2;
        while (arr[mid] != value) {
            if (arr[mid] > value) {
                max = mid - 1;
            } else if (arr[mid] < value) {
                min = mid + 1;
            }
            mid = (min + max) / 2;
            if (min > max) return -1;//如果最小索引大于最大索引证明没有找到这个value,要退出循环
        }
        return mid;//返回索引
    }

 题二:给定一个数组,写一个函数,将数组中的0都挪到数组的末尾,而维持其他非0元素的相对位置

//实验数据
int[] nums = {0,1,0,3,12};
//排序后
nums = {1,3,12,0,0}

思路:将所有非0元素拿出来,放在按顺序放在一个数组中,然后将最后的位置全部塞进0

public ArrayList moveZero(int[] nums) {
        ArrayList arrayList = new ArrayList();
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != 0) {
                arrayList.add(nums[i]);
            }
        }
        int diff = nums.length - arrayList.size();
        if (diff == 0) {
            return arrayList;
        } else {
            for (int i = 0; i < diff; i++) {
                arrayList.add(0);
            }
            return arrayList;
        }
    }

 思路二:遍历所有数组,将非0元素都放在前K位,剩余的都填充0

public int[] moveZero2(int[] nums) {
        int k = 0;//在数组nums中,[0...k) 均为非0元素
        //思路:在遍历的[0...i]个元素的数组中,所有的非0元素都按照顺序在[0...k)中
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] != 0) { //如果是非0元素,将该元素放在k位置
                nums[k] = nums[i];
                k++; //k++
            }
        }
        //将剩余位置,都放置为0
        for (int i = k; i < nums.length; i++) {
            nums[i] = 0;
        }
        return nums;
    }

 题目三:给n个元素的数组,元素取值只有0,1,2三种可能,请为这个数组进行排序

思路一:使用计数排序,适用于元素个数非常有限的情况。遍历数据0,1,2的分别的元素个数,然后按照数值大小,在对应的位置分别放置多少个元素即可

public int[] sortColors(int[] nums) {
        int[] counts = {0, 0, 0};
        // 遍历数组,查出数值个数
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == 0) {
                counts[0]++;
            } else if (nums[i] == 1) {
                counts[1]++;
            } else if (nums[i] == 2) {
                counts[2]++;
            } else {
                return null;
            }
        }
        int index = 0;
        for (int i = 0; i < counts.length; i++) { //按照顺序塞入值
            for (int j = 0; j < counts[i]; j++) {
                nums[index] = i;
                index++;
            }
        }
        return nums;
    }

 思路二:三路快排,只需遍历一次即可: 将数组分为三部分,第一部分全是0 ,第二部分全是1,第三部分全是2。对第二部进行遍历:如果值=1,则往后遍历一位;如果值=2,将第三部分的左侧边界往左移动一位,并将i和左侧边界值交换位置(放在第三部分的最前端),i的值不变;同理,如果值=0,将第一部分的右侧值往右移动一位,并将i和右侧边界交换位置,(放在第一部分的最右端),i的值不变

public int[] sortColors2(int[] nums) {
        // 分为三部分,第一部分全是0 ,第二部分全是1,第三部分全是2
        //初始化索引值
        int zero = -1;//nums[0,zero] 第一部分
        int two = nums.length;//nums[two,length-1] 第三部分

        for (int i = 0; i < two; ) {
            if (nums[i] == 1) {
                i++;
            } else if (nums[i] == 2) {
                two--; //第三部分的左侧边界,往左减一位
                swap(nums, two, i); //将i和two交换位置
            } else if (nums[i] == 0) {
                zero++; //第一部分的右侧边界,往右加一位
                swap(nums, zero, i);
            } else {
                return null;
            }
        }
        return nums;
    }

// 交换数组元素
    public static void swap(int[] array, int x, int y) {
        int xx = array[x];
        int yy = array[y];
        array[x] = yy;
        array[y] = xx;
    }

 题四:在n长度的数组中,找到第k大的数值

题五:给定一个有序整型数组和整型数target,在数组中找两个元素,使其相加和为target,并返回开两个元素的索引

int[] nums = {2,7,11,15};
int target = 9;
//结果返回的索引就是:1,2(索引从1开始算)

思路:使用二分查找,nums[i] 在剩余数组(也是有序的)中,寻找target-nums[i] (每一次遍历,都使用一次二分查找)

思路二:对撞指针,(双指针)一个指针在数组首,一个指针在数组尾,两个指针不停的往中间移动 O(n)

public int[] twoSum(int[] arr, int target) {
        if (arr.length < 2) return null;
        int l = 0;
        int r = arr.length - 1;
        int res[] = {0, 0};
        while (l < r) {
            if ((arr[l] + arr[r]) == target) {
                res[0] = l + 1;
                res[1] = r + 1;
                return res; //返回索引数组
            } else if ((arr[l] + arr[r]) < target) {
                l++; //最左侧往右移一位
            } else {
                r--; //最右侧往左移一位
            }
        }
        throw null; //如果没有找到,抛出异常
    }

题六:给定一个数组和数字s,找到数组中的最短连续子数组,使得连续子数组的数字和sum>=s,返回这个最短子数组的长度

//实验数据
int[] nums={2,3,1,2,4,3};
int s = 7;
//输出结果:子数组[3,4],长度为2

 思路:滑动窗口,子数组[l,r],当子数组的和<s时,将子数组的右侧往右移动,子数组增加一位;当子数组的和>=s时,将子数组的左侧往右移一位,子数组减少一位。

 public int minSubArr(int[] nums, int s) {
        int l = 0, r = -1; //nums[l...r]是我们的滑动窗口
        int sum = 0;
        int res = nums.length + 1;

        while (l < nums.length) { //左边界 < 长度
            if (r + 1 < nums.length && sum < s) { //当前窗口的和 <s
                r++; //将右边界,往右移动,增加一位
                sum += nums[r];
            } else {
          l++; //将左边界,往右移动,减少一位 sum -= nums[l]; } if (sum >= s) { res = min(res, r - l + 1); } } if (res == nums.length + 1) { //如果没有,则返回0 return 0; } return res; } //求最小值 public int min(int i, int j) { if (i < j) { return i; } else { return j; } }

 题七:寻找字符串中,没有重复字母的最长子字符串

//示例数据:
    "abcabcbb" -> "abc"
    "nnnnn" -> "n"
    "pwwkew" -> "wke"

 思路:滑动窗口 ,滑动窗口的长度并不是固定不变的。每次对比下一个字符是否出现在子字符串时,使用一个频率数组,记录每个字符在子字符串中出现的频率。如果为0,那就代表没有在子字符串中出现过;如果非0,就代表出现过

原文地址:https://www.cnblogs.com/starstarstar/p/11194991.html