只出现一次的数字——Leetcode

代码实现:

第一次想到用map,虽然能得到正确结果,但是不符合不用额外内存的要求

    //用map 不符合不使用额外空间
    public int singleNumber1(int[] nums) {
        int temp = 0;
        Map<Integer, Boolean> map = new HashMap<>();
        for (int i = 0; i < nums.length; i++) {
            if (map.containsKey(nums[i])) {
                map.put(nums[i], false);
                continue;
            }
            map.put(nums[i], true);
        }

        for (int i = 0; i < nums.length; i++) {
            if (map.get(nums[i])) {
                temp = nums[i];
                break;
            }
        }

        return temp;
    }

第二次想到堆排序,堆排序时间复杂度是NLogN,空间复杂度是常数级别:

public static void main(String[] args) {
        SingleNumber singleNumber = new SingleNumber();
        int[] arr = {4, 1, 2, 1, 2};
        singleNumber.singleNumber(arr);
    }

    //用堆排序,时间复杂度是 O(NLogN)
    public int singleNumber2(int[] nums) {
        heapSort(nums);
        int temp = 0;
        for (int i = 0; i < nums.length; i++) {
            if (i == nums.length - 1) {
                temp = nums[i];
                break;
            }
            if (nums[i] == nums[i + 1]) {
                i++;
            } else {
                temp = nums[i];
                break;
            }
        }
        return temp;
    }


    public static void heapSort(int[] sortArr) {
        buildHeap(sortArr);
        int n = sortArr.length - 1;
        while (n > 0) {
            int temp = sortArr[0]; //把根节点和最后一个元素交换
            sortArr[0] = sortArr[n];
            sortArr[n] = temp;
            n--; // 交换之后,最后一个元素是最大的了,以后没必要在比较这个元素,所以n--
            shiftDown(0, n, sortArr);
        }
    }

    //自顶向下建堆,时间复杂度是O(nlog2n),空间复杂度是常数级别的,也没有达到不实用额外内存空间的要求
    public static void buildHeap(int[] sortArr) {
        for (int i = 1; i < sortArr.length; i++) {
            shiftUp(i, sortArr);
        }
    }

    //在插入的时候,一般都是插入到末尾,所以需要向上调 index 是插入数的索引
    public static void shiftUp(int index, int[] sortArr) {
        int parentIndex = (index - 1) / 2;
        if (index > 0) {
            if (sortArr[index] > sortArr[parentIndex]) {
                int temp = sortArr[index];
                sortArr[index] = sortArr[parentIndex];
                sortArr[parentIndex] = temp;
                shiftUp(parentIndex, sortArr);
            }
        }
    }

    //在删除根结点的时候,一般都是拿末尾的数来替换,所以需要向下调整 index 删除的节点的索引
    public static void shiftDown(int index, int end, int[] sortArr) {
        int sunLeft = 2 * index + 1; // 左孩子的索引
        int sunRight = 2 * index + 2; // 右孩子的索引

        //如果两个孩子都不是null
        //堆的兄弟节点是无序的,所以需要比较出哪个节点更大,和更大的那个交换
        if (sunLeft <= end && sunRight <= end) {
            if (sortArr[sunLeft] >= sortArr[sunRight]) {
                if (sortArr[index] < sortArr[sunLeft]) {
                    int temp = sortArr[index];
                    sortArr[index] = sortArr[sunLeft];
                    sortArr[sunLeft] = temp;
                    shiftDown(sunLeft, end, sortArr);
                }
            } else {
                if (sortArr[index] < sortArr[sunRight]) {
                    int temp = sortArr[index];
                    sortArr[index] = sortArr[sunRight];
                    sortArr[sunRight] = temp;
                    shiftDown(sunRight, end, sortArr);
                }
            }
        } else if (sunLeft <= end) {
            if (sortArr[index] < sortArr[sunLeft]) {
                int temp = sortArr[index];
                sortArr[index] = sortArr[sunLeft];
                sortArr[sunLeft] = temp;
                shiftDown(sunLeft, end, sortArr);
            }
        }
    }

看别人的答案,用位运算异或:

//注意:记住以后要求不能使用额外空间的时候,往位运算想想
//这里使用位异或运算 相同为 0 不同为 1 例如 4 ^ 1 = 0100 ^ 0001 = 0101
/**
 * 交换律:a ^ b ^ c <=> a ^ c ^ b
 * <p>
 * 任何数于0异或为任何数 0 ^ n => n
 * <p>
 * 相同的数异或为0: n ^ n => 0
 * <p>
 * var a = [2,3,2,4,4]
 * <p>
 * 2 ^ 3 ^ 2 ^ 4 ^ 4等价于 2 ^ 2 ^ 4 ^ 4 ^ 3 => 0 ^ 0 ^3 => 3
 */
    //注意:记住以后要求不能使用额外空间的时候,往位运算想想
    //这里使用位异或运算 相同为 0 不同为 1 例如 4 ^ 1 = 0100 ^ 0001 = 0101
    /**
     * 交换律:a ^ b ^ c <=> a ^ c ^ b
     * <p>
     * 任何数于0异或为任何数 0 ^ n => n
     * <p>
     * 相同的数异或为0: n ^ n => 0
     * <p>
     * var a = [2,3,2,4,4]
     * <p>
     * 2 ^ 3 ^ 2 ^ 4 ^ 4等价于 2 ^ 2 ^ 4 ^ 4 ^ 3 => 0 ^ 0 ^3 => 3
     */
    public int singleNumber(int[] nums) {
        for (int i = 1; i < nums.length; i++) {
            nums[0] = nums[i] ^ nums[0];
        }
        return nums[0];
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值