数组

140 阅读4分钟

一、数组的增删改查

1.数组的初始化

/**
 * 初始化数组
 */
public static void init() {
    int[] a1 = new int[]{1, 2, 3, 4, 5};
    int[] a2 = {1, 2, 3, 4, 5};
    int[] a3 = new int[5];
    for (int index = 0; index < a3.length; index++) {
        a3[index] = index + 1;
    }
}

2.根据索引查找

/**
 * 根据索引查找
 * @param array 数组
 * @param size 数组大小
 * @param index 要查找的目标元素的索引
 * @return 查找到的元素
 * @throws Exception 异常
 */
public static int findByIndex(int[] array, int size, int index) throws Exception {
    if (index >= size || index < 0) {
        throw new Exception("index不合法!");
    }
    return array[index];
}

3.根据元素查找

/**
 * 根据元素查找
 * @param array 数组
 * @param size 数组大小
 * @param item 要查找的目标元素
 * @return 查找到的元素
 * @throws Exception 异常
 */
public static int findByItem(int[] array, int size, int item) throws Exception {
    for (int index = 0; index < size; index++) {
        if (array[index] == item) {
            return index;
        }
    }
    return -1;
}

4.在指定位置插入

/**
 * 在指定位置插入
 * @param array 数组
 * @param size 数组大小
 * @param item 要插入的元素
 * @param index 插入的位置
 * @throws Exception 异常
 */
public static void addByIndex(int[] array, int size, int item, int index) throws Exception {
    if (size > array.length - 1) {
        throw new Exception("数组已满,不能再插入!");
    }
    if (index > array.length - 1 || index < 0) {
        throw new Exception("index不合法!");
    }
    for (int i = size - 1; i >= index; i--) {
        array[i + 1] = array[i];
    }
    array[index] = item;
    size++;
}

5.有序数组中插入元素

/**
 * 有序数组中插入元素
 * @param array 有序数组
 * @param size 数组中已有元素的个数
 * @param item 要插入的数据
 * @throws Exception 异常
 */
public static void addItemSequence(int[] array, int size, int item) throws Exception {
    if (size > array.length - 1) {
        throw new Exception("数组已满,不能再插入!");
    }
    if (size < 0) {
        throw new Exception("size输入不合法!");
    }
    int key = size;
    for (int i = 0; i < size; i++) {
        if (item < array[i]) {
            key = i;
            break;
        }
    }
    for (int i = size - 1; i >= key; i--) {
        array[i + 1] = array[i];
    }
    array[key] = item;
    size++;
}

6.根据索引删除

/**
 * 根据索引删除
 * @param array 数组
 * @param size 数组已有元素个数
 * @param index 索引
 * @throws Exception 异常
 */
public static void removeByIndex(int[] array, int size, int index) throws Exception {
    if (size < 0) {
        throw new Exception("size输入不合法!");
    }
    if (size == 0) {
        return;
    }
    if (index > array.length - 1 || index < 0 || index >= size) {
        throw new Exception("index输入不合法!");
    }
    for (int i = index; i < size - 1; i++) {
        array[i] = array[i + 1];
    }
    array[size - 1] = 0;
}

7.根据元素删除

/**
 * 根据元素删除
 * @param array 数组
 * @param size 数组已有元素个数
 * @param item 索引
 * @throws Exception 异常
 */
public static void removeByItem(int[] array, int size, int item) throws Exception {
    if (size < 0) {
        throw new Exception("size输入不合法!");
    }
    if (size == 0) {
        return;
    }
    int index = -1;
    for (int i = 0; i < size; i++) {
        if (array[i] == item) {
            index = i;
            break;
        }
    }
    if (index == -1) {
        return;
    }
    removeByIndex(array, size, index);
}

二、数组的合并

案例

给你两个按⾮递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数⽬。 请你合并 nums2 到 nums1 中,使合并后的数组同样按非递减顺序排列。 注意:最终,合并后数组不应由函数返回,⽽是存储在数组 nums1 中。为了应对这种情况,nums1 的初始⻓度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的⻓度为 n 。 例⼦1: 输⼊:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3 输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6]。\

方法一:直接在num1的m索引处往后面加,加完再排序

public static void merge1(int[] a1, int[] a2, int m, int n) {
    for (int index = m - n; index < m; index++) {
        a1[index] = a2[index - n];
    }
    Arrays.sort(a1);
}

方法二:一边合并一边排序,最大值应该合并后的最大索引的位置。

public static void merge2(int[] a1, int[] a2, int m, int n) {
    int length = m - 1;
    int len1 = m - n - 1;
    int len2 = n - 1;
    while (len1 >= 0 && len2 >= 0) {
        if (a1[len1] >= a2[len2]) {
            a1[length--] = a1[len1--];
        } else {
            a1[length--] = a2[len2--];
        }
    }
    while (len2 >= 0) {
        a1[length--] = a2[len2--];
    }
}

三、字符串替换

案例

给定字符串"we are Chinese!",将其中空格替换成%#$

方法一:新创建一个字符串,一边遍历旧的字符串一边判断是否是空格,如果是空格就在原来的基础上加%#$

public static String replace1(String str) {
    if (str == null) {
        return null;
    }
    String strNew = "";
    char[] chars = str.toCharArray();
    for (char aChar : chars) {
        if (aChar == ' ') {
            strNew += "%#$";
        } else {
            strNew += aChar;
        }
    }
    return strNew;
}

方法二:先统计空格的个数,每替换一个空格字符串的长度就加2,新的字符串的长度=老的字符串长度+空格数量*2。定义两个指针,一个指向新字符串末尾,一个指向老字符串末尾,从后往前遍历,如果是空格就替换,指针前移三位。

public static String replace2(String str) {
    if (str == null) {
        return null;
    }
    int count = 0;
    for (int index = 0;index < str.length();index++) {
        char c = str.charAt(index);
        if (c == ' ') {
            count++;
        }
    }
    int oldLength = str.length() - 1;
    int newLength = str.length() + 2 * count - 1;
    StringBuilder stringBuilder = new StringBuilder(str);
    stringBuilder.setLength(newLength + 1);
    while ((oldLength >= 0 && newLength > oldLength)) {
        char c = str.charAt(oldLength);
        if (c == ' ') {
            stringBuilder.setCharAt(newLength--, '$');
            stringBuilder.setCharAt(newLength--, '#');
            stringBuilder.setCharAt(newLength--, '%');
        } else {
            stringBuilder.setCharAt(newLength--, c);
        }
        oldLength--;
    }
    return stringBuilder.toString();
}

四、删除数组中指定元素

案例

给定一个数组,删除数组中指定元素,并返回新数组的长度 如数组{1, 2, 3, 4, 5},删除3,返回4

方法一:不新开辟空间,新的数组有效长度以统计的个数为准,大于统计的个数索引后面的元素不考虑。例如统计的新数组有效长度是5,那么4索引位置以后的元素作废。

public static int remove1(int[] nums, int val) {
    int count = 0;
    for (int index = 0; index < nums.length; index++) {
        if (nums[index] != val) {
            nums[count++] = nums[index];
        }
    }
    return count;
}

方法二:新创建一个数组,循环判断是否等于给定元素,不等于就放入新数组中。

public static int length(int[] nums, int num) {
    int count = 0;
    for (int index = 0; index < nums.length; index++) {
        if (nums[index] == num) {
            count++;
        }
    }
    int oldLength = nums.length - 1;
    int len = nums.length - count;
    int[] newNum = new int[len];
    while (oldLength > 0) {
        if (nums[oldLength] != num) {
            newNum[--len] = nums[oldLength];
        }
        oldLength--;
    }
    return newNum.length;
}

五、删除有序数组中重复元素,使每个元素只出现一次

案例

给定数组{1, 2, 2, 3, 3},删除后返回{1, 2, 3}

public static int remove2(int[] array) {
    int length = array.length;
    int j = 1;
    for (int index = 1; index < length; index++) {
        if (array[index] != array[j - 1]) {
            array[j] = array[index];
            j++;
        }
    }
    return j;
}

六、元素奇数偶数移动问题

案例

给定数组{1,2, 3, 4},输出{2,4,1,3},偶数放前面,奇数放后面,输出{4,2,1,3}和{4,2,3,1}也是可以的,元素顺序不影响,只要偶数在一起,奇数在一起。

方法一:暴力破解,遍历两次,第一次获取是偶数的元素,第二次获取是奇数的元素,

public static int[] order1(int[] array) {
    int[] a = new int[array.length];
    int j = 0;
    for (int i = 0; i < array.length; i++) {
        if (array[i] % 2 == 0) {
            a[j] = array[i];
            j++;
        }
    }
    for (int i = 0; i < array.length; i++) {
        if (array[i] % 2 != 0) {
            a[j] = array[i];
            j++;
        }
    }
    return a;
}

方法二:双指针遍历,如果是偶数就把偶数放在前面,和他后面的元素交换位置

public static int[] order2(int[] array) {
    int i = 0;
    int j = array.length;
    for (int index = 0; index < j; index++) {
        if (array[index] % 2 == 0) {
            int temp = array[i];
            array[i] = array[index];
            array[index] = temp;
            i++;
        }
    }
    return array;
}

七、数组移动

案例

给你⼀个数组,将数组中的元素向右轮转 k 个位置,其中 k 是⾮负数。 例如: 输⼊: nums = [1,2,3,4,5,6,7], k = 3 输出: [5,6,7,1,2,3,4] 解释: 向右轮转 1 步: [7,1,2,3,4,5,6] 向右轮转 2 步: [6,7,1,2,3,4,5] 向右轮转 3 步: [5,6,7,1,2,3,4] \

解答:先把整个数组翻转,然后从0到k处翻转,然后从k到数组长度翻转

public static void reverse(int[] array, int start, int end) {
    while (start < end) {
        int temp = array[start];
        array[start] = array[end];
        array[end] = temp;
        start++;
        end--;
    }
}

public static void rotate(int[] array, int k) {
    reverse(array, 0, array.length - 1);
    reverse(array, 0, k - 1);
    reverse(array, k, array.length - 1);
}

八、数组加一

案例

给定正整数数组,实现数组的整数值加一。给出数组{1,2,3},输出{1,2,4};输入{9,9,9},输出{1,0,0,0}

方法一:从末位开始往前面计算,判断是否需要进位,进位就把当前位置置0,否则退出循环。如果一直到最后一位都需要进位,那么需要申请一个原来数组长度+1的数组进行存储。

public static int[] add1(int[] array) {
    int length = array.length - 1;
    int newLength = array.length;
    int last = array[length];
    int result = last + 1;
    if (result == 10) {
        while (length > 0 && result == 10) {
            array[length] = 0;
            length--;
            result = array[length] + 1;
        }
        array[length] = array[length] + 1;
        if (array[length] == 10) {
            array[length] = 1;
        }
    } else {
        array[length] = result;
    }
    if (result == 10) {
        int[] arr = new int[newLength + 1];
        arr[0] = 1;
        return arr;
    }
    return array;
}

方法二:从后往前循环遍历,给每个位置加一,再对10取余,不等于0直接返回。

public static int[] add2(int[] array) {
    for (int index = array.length - 1; index >= 0; index--) {
        array[index]++;
        array[index] %= 10;
        if (array[index] != 0) {
            return array;
        }
    }
    int[] arr = new int[array.length + 1];
    arr[0] = 1;
    return arr;
}

九、数组和指定数字相加

案例

给出数组{1,2,3,4},和数组1234相加,输出{2,4,6,8};给出数组{9,9,9,9}和数字9999,输出{1,9,9,9,8}

解法:

将数组转换成数字,和数字相加,再转换成数组

public static int[] add4(int[] array, int val) {
    int count = 0;
    for (int index = array.length - 1; index >= 0; index--) {
        int first = array[index];
        count = count + first * (int)Math.pow(10, array.length - index - 1);
    }
    int result = count + val;
    int resultNum = result;
    int n = 0;
    while (result / 10 > 0) {
        result = result / 10;
        n++;
    }
    n++;
    int[] arr = new int[n];
    for (int index = n - 1; index >= 0; index--) {
        arr[index] = resultNum % 10;
        resultNum = resultNum / 10;
    }
    return arr;
}


public static int power(int num, int power) {
    if (power == 0) {
        return 1;
    }
    int result = num;
    for (int index = 1;index < power; index++) {
        result = result * result;
    }
    return result;
}

十、字符串相加

案例

例如"123"加"456",输出"579"
这里还是采用双指针的思想,从低位开始加

private static String add1(String num1, String num2) {
    int i = num1.length() - 1;
    int j = num2.length() - 1;
    int add = 0;
    StringBuilder stringBuilder = new StringBuilder();
    while (i >= 0 || j >= 0 || add != 0) {
        int x = 0;
        int y = 0;
        if (i >= 0) {
            x = num1.charAt(i) - '0';
        }
        if (j >= 0) {
            y = num2.charAt(j) - '0';
        }
        int result = x + y + add;
        stringBuilder.append(result % 10);
        add = result / 10;
        i--;
        j--;
    }
    stringBuilder.reverse();
    return stringBuilder.toString();
}

案例:

变形题:二进制字符串加法,原理相同,只不过是逢二进一

private static String add2(String num1, String num2) {
    int i = num1.length() - 1;
    int j = num2.length() - 1;
    int add = 0;
    StringBuilder stringBuilder = new StringBuilder();
    while (i >= 0 || j >= 0 || add != 0) {
        int x = 0;
        int y = 0;
        if (i >= 0) {
            x = num1.charAt(i) - '0';
        }
        if (j >= 0) {
            y = num2.charAt(j) - '0';
        }
        int result = x + y + add;
        stringBuilder.append(result % 2);
        add = result / 2;
        i--;
        j--;
    }
    stringBuilder.reverse();
    return stringBuilder.toString();
}

十一、找出数组中出现次数超过一半的数字

案例

给出数组{1,2,1,2,1},输出1,如果没有次数最多的数字则输出0,如{1,1,2,2},输出0

方法一:排序找中位数,中位数一定是次数最多的,如果没有超过一半那就是没有

public static int overHalf1(int[] nums) {
    int length = nums.length;
    for (int i = 0; i < length; i++) {
        for (int j = 0; j < length - i - 1; j++) {
            if (nums[j] > nums[j + 1]) {
                int temp = nums[j];
                nums[j] = nums[j + 1];
                nums[j + 1] = temp;
            }
        }
    }
    int num = 0;
    if (length % 2 == 0) {
        num = (nums[length / 2 - 1] + nums[length / 2]) / 2;
    } else {
        num = (nums[length / 2]);
    }
    int count = 0;
    for (int index = 0; index < length; index++) {
        if (nums[index] == num) {
            count++;
        }
    }
    if (count > length / 2) {
        return num;
    }
    return 0;
}

方法二:利用map,key存数组,value存出现的次数

public static int overHalf2(int[] nums) {
   Map<Integer, Integer> map = new LinkedHashMap<>();
   int length = nums.length;
    for (int num : nums) {
        map.put(num, map.getOrDefault(num, 0) + 1);
        if (map.get(num) > (length / 2)) {
            return num;
        }
    }
   return 0;
}

方法三:计数法,设置初始出现次数为1,从第二个元素开始遍历,如果下一个元素还是这个元素就给次数+1,否则就减一。

public static int overHalf3(int[] nums) {
    int length = nums.length;
    int result = nums[0];
    int times = 1;
    for (int index = 1; index < length; index++) {
        if (times == 0) {
            result = nums[index];
            times++;
            continue;
        }
        if (nums[index] == result) {
            times++;
        } else {
            times--;
        }
    }
    times = 0;
    for (int num : nums) {
        if (num == result) {
            times++;
        }
    }
    if (times > (length / 2)) {
        return result;
    }
    return 0;
}

十二、找出数组中只出现一次的数字

例如{1,2,2,3,3},输出1

方法一:两次for循环搞定,设置计数器初始值为1,如果出现重复值就加一,一次循环结束判断计数器是否还是1,如果还是1就是要找的数。

public static int oneTimes1(int[] nums) {
    int length = nums.length;
    
    for (int i = 0; i < length; i++) {
        int times = 1;
        int result = nums[i];
        for (int j = 0; j < length; j++) {
            if (nums[j] == nums[i] && i != j) {
                times++;
            }
        }
        if (times == 1) {
            return result;
        }
    }
    return 0;
}

方法二:用异或

public static int oneTimes2(int[] nums) {
    int result = 0;
    for (int num : nums) {
        result ^= num;
    }
    return result;
}