剑指offer(算法题)

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

输入:
[2, 3, 1, 0, 2, 5, 3]
输出: 2 或 3

/**
     * 查找重复的数字
     *
     * @param arr 指定数组
     * @return int 未找到返回-1
     * @author Huikf
     * @since 18:42 2022/3/20
     */
    public static int getRepeatNum(int[] arr) {
        Set<Integer> set = new HashSet<>();
        for (int i : arr) {
            if (set.contains(i)) {
                return i;
            }
            set.add(i);
        }
        return -1;
    }

提示:

进阶:
如何证明 n u m s numsnums 中至少存在一个重复的数字?
你可以在不修改数组 n u m s numsnums 的情况下解决这个问题吗?
你可以只用常量级 O ( 1 ) O(1)O(1) 的额外空间解决这个问题吗?
思路
不能修改原数组,故不能用移动元素让下标和值相对应的方法,也不能用排序的方法
只能用O(1)的空间,故不能用HashSet和新数组打卡标记的方法
时间复杂度小于O ( n 2 )
故不能用暴力嵌套两个for循环遍历数组两次的方法
1<=nums[i]<=n

  /**
     * 查找重复的数字
     * [2,3,3,2,5,4,6,7]
     *
     *
     * <p>
     * 采用二分查找的方法
     *
     * @param arr 指定数组
     * @return int
     * @author Huikf
     * @since 18:42 2022/3/20
     */
    public static int getRepeatNum(int[] arr) {
        //最小值
        int left = 1;
        //最大值
        int right = arr.length - 1;
        while (left < right) {
            //中间值
            int mid = (left + right) / 2;
            //获取在这个区间数组中元素在这个区间出现的次数,
            //正常来说left-mid+1 刚好等于这个count,说明没有重复 ,如上述数组 1~4之间count=4(mid-left+1),
            //但实际上count=5,说明在[left,mid]区间中有重复值,所以把mid赋值给right,即在[1,4]中寻找重复值,直到退出循环
            int count = getCount(arr, left, mid);
            if (count > (mid - left + 1)) {
                //在左边
                right = mid;
            } else {
                left = mid + 1;
            }
        }
        return left;
    }

    private static int getCount(int[] arr, int left, int mid) {
        int count = 0;
        for (int i : arr) {
            if (i >= left && i <= mid) {
                count++;
            }
        }
        return count;
    }

04:二维数组中的查找

 /**
     * 一个数字是否存在矩阵,该矩阵横向竖向递增
     * <p>
     * 思路:从右上方开始查找 比右上方大x--,小则y++,直到相等
     *
     * @param matrix 二维矩阵
     * @param target 目标值
     * @return boolean
     * @author Huikf
     * @since 19:49 2022/3/20
     */
    public static boolean isExist(int[][] matrix, int target) {
        if (matrix == null || matrix.length == 0 || matrix[0].length == 0) {
            return false;
        }
        //右上方坐标
        int x = matrix.length - 1;
        int y = 0;
        while (x >= 0 && y <= matrix[0].length - 1) {
            if (matrix[x][y] == target) {
                return true;
            } else if (matrix[x][y] > target) {
                x--;
            } else {
                y++;
            }
        }
        return false;
    }

05 3.替换空格

    /**
     * 字符串替换 空格替换成%20
     *
     * @param s 输入字符串
     * @return java.lang.String
     * @author Huikf
     * @since 19:59 2022/3/20
     */
    public static String replaceSpace(String s) {
        StringBuilder sb = new StringBuilder();
        for (char c : s.toCharArray()) {
            if (c == ' ') {
                sb.append("%20");
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

合并有序数组

  /**
     * 合并有序数组
     * 数组A的长度=A的长度+B的长度
     * 采用双指针法
     *
     * @param A A数组
     * @param m A数组长度
     * @param B B数组
     * @param n B数组长度
     * @author Huikf
     * @since 21:26 2022/3/20
     */
    public void mergeSortArr(int[] A, int m, int[] B, int n) {
        //指向A数组最后元素的位置
        int last1 = m - 1;
        //指向B数组最后元素的位置
        int last2 = n - 1;
        //指向拼接后插入的位置
        int last = m + n - 1;
        while (last1 >= 0 && last2 >= 0) {
            if (A[last1] >= B[last2]) {
                A[last] = A[last1];
                last1--;
            } else {
                A[last] = B[last2];
                last2--;
            }
            last--;
        }
        //当last1<0(数组B有剩余)时退出,然后将未遍历完的B数组拷贝到A数组中。
        //或者last2<0(数组A有剩余)时退出,这时,说明B数组已经全部合并到A数组中,这下面该意思为:把B数组从0位置到last2+1位置元素拷贝到A数组的从0起始位置
        System.arraycopy(B, 0, A, 0, last2 + 1);
    }

06 4.从尾到头打印链表

    public static int[] reversePrint(ListNode head) {

        if (head == null) {
            return new int[]{};
        }
        Stack<Integer> stack = new Stack<>();
        ListNode cur = head;
        while (cur != null) {
            stack.push(cur.val);
            cur = cur.next;
        }
        int[] arr = new int[stack.size()];
        for (int i = 0; i < arr.length; i++) {
            arr[i] = stack.pop();
        }
        return arr;
    }

07 5.重构二叉树

、、

打印从1到最大的n位数

	/**
	 * 打印从1到最大的n位数
	 * 10^n-1
	 *
	 * @param n n
	 * @return int[]
	 * @author huikf
	 * @since 2022/3/22 10:55
	 */
	public int[] print(int n) {
		int v = (int) Math.pow(10, n) - 1;
		int[] res = new int[v];
		for (int i = 0; i < res.length; i++) {
			res[i] = i + 1;
		}
		return res;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值