0

Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.

My solution:

def findDuplicate(nums):
    slow = fast = finder = 0
    while fast is not None:
    
    
        slow = nums[slow]
        fast = nums[nums[fast]]
    
        if fast is slow:
            return slow
       
   return False

nums = [1,2,2,3,4]
print findDuplicate(nums)

My above solution works and gives me o/p 2 but it doesn't work for every input for example it doesn't work for [11,15,17,17,14] or [3,1,2,6,2,3] and gives me error IndexError: list index out of range. I am not able to find patterns and am not able to track down the exact problem. Also tried to change my while condition:

while fast is not None and nums[nums[fast]] is not None:

your help will be greatly appreciated! Thank you.

Yilmaz
  • 35,338
  • 10
  • 157
  • 202
Aarya
  • 33
  • 1
  • 3
  • what is your desired output – Hisham Karam Oct 21 '16 at 02:28
  • 1
    I believe your first example, `[11,15,17,17,14]`, does not satisfy the description of your problem: the list contains `5` elements, but the elements are not between 1 and `5 - 1 = 4`. For the second example, `[3,1,2,6,2,3]`, note that Python's lists are 0-indexed, and so 6 is out-of-bounds. That is, you have an off-by-one error. – jme Oct 21 '16 at 02:31
  • I want to find duplicate number from the array.@HishamKaram – Aarya Oct 21 '16 at 02:32
  • 1
    I believe the usual solution is to sort the array then look for two adjacent, equal values. Given the constraints and once sorted, the value at each index should be index+1. Once you find a value that isn't, you've found the an instance of the pair. The other instance will be at the previous index. – Ouroborus Oct 21 '16 at 02:33
  • this reads like homework. – UltrasoundJelly Oct 21 '16 at 02:35
  • As for a proof: If you have `n+1` integers and the values of the integers is `1 <= i <= n`, you'll always have at least one duplicate because the number of unique values is one less than the number of slots available. – Ouroborus Oct 21 '16 at 02:44
  • 1
    Unluckily I have to say that your code is not related to the given task. Basically there is something wrong with every single line in the function except of `return slow`. I advise to go back to the start and rethink your approach. – Klaus D. Oct 21 '16 at 02:50
  • 2
    Possible duplicate of [Find duplicate element in array in time O(n)](http://stackoverflow.com/questions/14944458/find-duplicate-element-in-array-in-time-on). The approach you are trying to take is the "cycle detection" approach. The code above may look a little strange, but it is on the right track towards a solution that takes `O(n)` and `O(1)` space. See [here](http://stackoverflow.com/a/37957711/1231929) for an answer which gives a full Python solution to this problem. – jme Oct 21 '16 at 03:16

6 Answers6

2

Since the numbers are between 1 and n and you have been told there is only one duplicate, you can use difference between the sum of the numbers in the array and the sum of numbers from 1 to n to get the duplicate.

def findDuplicate(l):
    n = len(l) - 1                     # Get n as length of list - 1
    return sum(l) - (n * (n + 1) / 2)  # n*(n+1)/2 is the sum of integers from 1 to n

So the duplicate is the sum of the list - n*(n+1)/2

Of course, this doesn't generalize to finding duplicates for any list. For that case, you need to use @Jalepeno112 's answer.

Munir
  • 3,442
  • 3
  • 19
  • 29
1

The fact that the first one works is a fluke. Let's look at what it does on the first pass.

nums = [1,2,2,3,4]
# slow starts as index 0.  So now, you've reassigned slow to be nums[0] which is 1.
# so slow equals 1
slow = nums[slow]

# now you are saying that fast equals nums[nums[0]].  
# nums[0] is 1.  nums[1] is 2
# so fast = 2        
fast = nums[nums[fast]]

On the next pass, slow will be nums[1] which is 2. fast will be nums[nums[2]] which is nums[2] which is 2. At this point slow and fast are equal.

In your second example, you are getting an IndexError because of fast = nums[nums[fast]] If the value at nums[fast] is not a valid index, then this code will fail. Specifically in the second example, nums[0] is 11. nums doesn't have an element at index 11, so you get an error.

What you really want to be doing is performing a nested for loop on the array:

# range(0,len(nums)-1) will give a list of numbers from [0, to the length of nums-1)
# range(1, len(nums)) does the same, 
# except it will start at 1 more than i is currently at (the next element in the array).  
# So it's range is recomputed on each outer loop to be [i+1, length of nums)
for i in range(0,len(nums)-1):
   for j in range(i+1,len(nums)):
       # if we find a matching element, return it
       if nums[i] == nums[j]:
           return nums[i]
# if we don't find anything return False
return False 

There are likely other more Pythonic ways to achieve this, but that wasn't your original question.

TheF1rstPancake
  • 2,318
  • 17
  • 17
0

first you must ensure all numbers in list satisfy your constrains.

to find duplicated numbers in a list Use Counter in collections it will return each number and number of occurrence example :

>>> from collections import Counter
>>> l=Counter([11,15,17,17,14])
>>> l
Counter({17: 2, 11: 1, 14: 1, 15: 1})

to get the most common one use :

>>> l.most_common(n=1)
[(17, 2)]

where n is the number most common numbers you want to get

Hisham Karam
  • 1,288
  • 17
  • 28
0
def duplicates(num_list):
    if type(num_list) is not list:
        print('No list provided')
            return
    if len(num_list) is 0 or len(num_list) is 1:
        print('No duplicates')
            return
    for index,numA in enumerate(num_list):
        num_len = len(num_list)
            for indexB in range(index+1, num_len):
                if numA == num_list[indexB]:
                    print('Duplicate Number:'+str(numA))
                        return
duplicates([11,15,17,17,14])
duplicates([3,1,2,6,2,3])
duplicates([])
duplicates([5])
kimobrian254
  • 557
  • 3
  • 10
0
l=[]
n= int(input("the number of digit is :"))
l=[0 for k in range(n)]
for j in range(0,n):
  l[j]=int(input("the component is"))
print(l)
b=0;  c=0
for i in range(n):
 if l[i]== l[n-1-i]:
    b=1;c=i
if b==1:
 print("duplicate found! it is",l[c])
elif b==0:
 print("no duplicate")
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Jan 23 '22 at 07:55
0

The answer is unfinished. It tries to convert the array to a linked list. So far it found where the slow pointer and fast pointer met, but this is the halfway solution. To get the solution, we need to initialize another pointer from the beginning of the linked list and walk towards each other. When they meet, that point is the where cycle is detected, in our question it is where the single point is:

class Solution:
    def findDuplicate(self, nums: List[int]) -> int:
        slow,fast=0,0
        while True:
            slow=nums[slow]
            fast=nums[nums[fast]]
            if slow==fast:
                break
        slow2=0
        while True:
            slow2=nums[slow2]
            slow=nums[slow]
            if slow==slow2:
                return slow2 
Yilmaz
  • 35,338
  • 10
  • 157
  • 202