剑指offer:找出数组中重复的数字

解法一.啥也别想直接暴力

先定义一个哈希表unordered_map<int,int> count,前面的int代表数组中的元素,后面的int代表出现的次数

//定义哈希表
unordered_map<int,int> count;
//找有没有重复元素
for(int i = 0;i < nums.size();i++) {
   count[nums[i]]++;
   if(count[nums[i] > 1 ) return nums[i];
}
return -1; // 到这里了说明循环结束了前面都没return,那么就说明没有找到重复元素 就需要返回-1了;

这题很简单,不过需要注意的是如果数字不在0~n-1 内 需要直接返回-1;所以在上面代码之前需要判断数组中的数字是否都在0~n-1内

// 注意注意
for(int i = 0;i < nums.size();i++) {
   if(nums[i] < 0 || nums[i] > nums.size()) 
   return -1;
}

好,现在需要将他们合体

1.核心代码模式

class Solution {
public:
    int duplicateInArray(vector<int>& nums) {
        unordered_map<int,int> count;
        for(int i = 0;i < nums.size();i++) {
            if(nums[i] < 0 || nums[i] > nums.size()) return -1;
        }
        for(int i = 0;i < nums.size();i++) {
            count[nums[i]] ++;
            if(count[nums[i]] > 1) return nums[i];
        }
        return -1;
        
    }
};
  1. ACM格式

#include<iostream>
#include<vector>
#include <unordered_map>

using namespace std;

class Solution {
public:
    int duplicateInArray(vector<int> &nums) {
        unordered_map<int,int> count;
        for(int i = 0;i < nums.size();i++) {
            if(nums[i] < 0 || nums[i] > nums.size()) return -1;
        }
        for(int i = 0;i < nums.size();i++) {
            count[nums[i]] ++;
            if(count[nums[i]] > 1) return nums[i];
        }
        return -1;
    }

};

int main() {
    //实例化一个对象
    Solution solution;
    vector<int> nums;
    int i;
    //控制台输入,遇到回车结束
    while(cin >> i) {
        nums.push_back(i);
        if(cin.get() == '\n') break;
    }
    int res = solution.duplicateInArray(nums);
    cout<<res;
    return 0;
}

这种方法的时间复杂度是O(N)的,只有一层循环,遍历一遍元素

但是空间复杂度可高了,有了个unordered_map,所以我们得找一个空间复杂度为O(1)的,就是在原数组上面操作,&引用符号已经提醒我们了,应该动原数组。什么方法好,等我找一找再写出来

有些人是用sort排序之后比较前后两个元素,但是sort是基于快排的,空间复杂读虽然是o(1)的,但是时间复杂度是O(nlogn)的

我们之前是如果数字不在0~n-1之内就return -1,所以如果没直接return,那么n个数肯定都是在0~n-1之内,这是一个重要的条件,说明n个数如果正好是0,1,2,.....,n-1才不会有重复数字,否则必有重复数字,毕竟只有n个数字,0到n-1就占了n个。所以我们就让0这个数占住第0个位置,1占住1这个位置,每个数占住自己的位置

怎么占坑呢,从第一个数字开始一直和它本该在的位置的数字进行交换,直到交换不动了,才交换下一个坑的数字

什么时候停止交换呢?当这个数字正好占住自己的坑位或者想要进行交换的数字和它一样就停止交换

看图

class Solution {
public:
    int duplicateInArray(vector<int>& nums) {
        int n = nums.size();
        for(auto x : nums)
        {
            if(x<0 or x>=n) return -1;
        }
        for(int i = 0;i < n;i++)
        {
            while(i != nums[i] and nums[i] != nums[nums[i]]) swap(nums[i],nums[nums[i]]);
            if(nums[i]!=i) return nums[i];
        }
        return -1;
    }
};

C++ ACW和上面一样 来一份Java版本

import java.util.Scanner;
import java.util.Vector;

public class Test {
    public static void swap(int a[],int i,int j) {
        int t = a[i];
        a[i] = a[j];
        a[j] = t;
    }
    public static int test(int[] nums) {
        int n = nums.length;
        for(int x : nums) {
            if(x < 0 || x >= n) return -1;
        }
        for(int i = 0;i < n;i++)
        {
            while(i != nums[i] && nums[i] != nums[nums[i]]) swap(nums,nums[i],nums[nums[i]]);
            if(nums[i]!=i) return nums[i];
        }
        return -1;
    }
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String str = in.next().toString();
        String[] arr = str.split(",");
        int[] b = new int[arr.length];
        for(int j = 0;j<b.length;j++)
        {
            b[j] = Integer.parseInt(arr[j]);
        }
        System.out.print(test(b));
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值