किसी संख्या के सभी विभाजकों को प्राप्त करने का सबसे अच्छा तरीका क्या है?


105

यहाँ बहुत ही गूंगा तरीका है:

def divisorGenerator(n):
    for i in xrange(1,n/2+1):
        if n%i == 0: yield i
    yield n

परिणाम जो मैं प्राप्त करना चाहता हूं वह इस एक के समान है, लेकिन मैं एक चालाक एल्गोरिथ्म चाहूंगा (यह एक बहुत धीमी और गूंगा है :-)

मुझे प्राइम फैक्टर और उनकी बहुलता काफी तेजी से मिल सकती है। मेरे पास एक जनरेटर है जो इस तरह से कारक उत्पन्न करता है:

(factor1, multiplicity1)
(factor2, multiplicity2)
(factor3, multiplicity3)
और इसी तरह ...

का उत्पादन

for i in factorGenerator(100):
    print i

है:

(2, 2)
(5, 2)

मैं नहीं जानता कि यह कितना उपयोगी है जो मैं करना चाहता हूं (मैंने इसे अन्य समस्याओं के लिए कोडित किया है), वैसे भी मैं इसे बनाने का एक स्मार्ट तरीका चाहूंगा

for i in divisorGen(100):
    print i

इसे आउटपुट करें:

1
2
4
5
10
20
25
50
100

अद्यतन: ग्रेग हेवगिल और उनके "स्मार्ट तरीके" के लिए बहुत धन्यवाद :) 100000000 के सभी विभाजकों की गणना करते हुए 0.01s ने 39 के खिलाफ अपने रास्ते से ले लिया कि गूंगा रास्ता मेरी मशीन पर ले गया, बहुत अच्छा: डी

UPDATE 2: यह कहना बंद करें कि यह इस पोस्ट का डुप्लिकेट है । किसी दिए गए नंबर के विभाजक की संख्या की गणना करने के लिए सभी विभाजकों की गणना करने की आवश्यकता नहीं है। यह एक अलग समस्या है, अगर आपको लगता है कि यह विकिपीडिया पर "डिवाइज़र फ़ंक्शन" की तलाश में नहीं है। पोस्ट करने से पहले सवाल और जवाब पढ़ें, अगर आपको समझ नहीं आ रहा है कि क्या विषय है तो बस उपयोगी नहीं जोड़ें और पहले से ही दिए गए उत्तर।


कारण यह है कि यह सुझाव दिया गया था कि यह प्रश्न "किसी दिए गए नंबर के विभाजकों की संख्या की गणना करने के लिए एल्गोरिथ्म" का लगभग एक डुप्लिकेट था, यह था कि उस प्रश्न में सुझाया गया पहला कदम सभी विभाजकों को खोजना था , जो मुझे विश्वास है कि वास्तव में है आप क्या करने की कोशिश कर रहे थे?
एंड्रयू एडगेकोम्बे

4
एंड्रयू को यह पता लगाने के लिए कि आपके पास कितने विभाजक हैं, बस आपको मुख्य कारक ढूंढने होंगे और फिर उनका उपयोग यह गिनने के लिए करना होगा कि कितने भाजक हो सकते हैं। विभाजक खोजना उस मामले में आवश्यक नहीं है।
Locc Faure-Lacroix

1
@ और अंबू, कृपया आप सही नाम
खनिजों का

जवाबों:


77

आपके factorGeneratorकार्य को देखते हुए , यहाँ एक divisorGenकाम करना चाहिए:

def divisorGen(n):
    factors = list(factorGenerator(n))
    nfactors = len(factors)
    f = [0] * nfactors
    while True:
        yield reduce(lambda x, y: x*y, [factors[x][0]**f[x] for x in range(nfactors)], 1)
        i = 0
        while True:
            f[i] += 1
            if f[i] <= factors[i][1]:
                break
            f[i] = 0
            i += 1
            if i >= nfactors:
                return

इस एल्गोरिथ्म की समग्र दक्षता पूरी तरह से की दक्षता पर निर्भर करेगी factorGenerator


2
वाह यह 39 के खिलाफ 100000000 के सभी भाजक की गणना के लिए 0.01 लिया कि गूंगा रास्ता (n / 2 पर रोक) बहुत अच्छा लगा, धन्यवाद!
एंड्रिया अंबू

47
हममें से जो पायथन को नहीं समझते हैं, उनके लिए यह वास्तव में क्या है?
मैथ्यू शार्ले

1
मोनोऑक्साइड: यह दिए गए कारकों के सभी गुणक संयोजनों की गणना करता है। इसमें से अधिकांश स्व-व्याख्यात्मक होना चाहिए; "यील्ड" लाइन रिटर्न की तरह है, लेकिन वैल्यू लौटाने के बाद भी चलती रहती है। [०] * nfactors लंबाई nfactors के शून्य की एक सूची बनाता है। घटाना (...) कारकों के उत्पाद की गणना करता है।
ग्रेग हेविगेल

कम और लैम्ब्डा संकेतन वे हिस्से थे जो वास्तव में मुझे भ्रमित कर रहे थे। मैंने सी # में ऐसा करने के लिए एक एल्गोरिथ्म को लागू करने की कोशिश की # कारकों की सरणी चलने के लिए एक पुनरावर्ती कार्य का उपयोग करके और उन सभी को एक साथ गुणा करें, लेकिन ऐसा लगता है कि 1024 जैसे नंबरों पर भयानक प्रदर्शन हुआ है जिसमें कई कारक हैं
मैथ्यू शार्ले

3
यह निश्चित रूप से नाटकीय रूप से n / 2 या sqrt (n) तक की प्रत्येक संख्या को विभाजित करने से बेहतर है, लेकिन इस विशेष कार्यान्वयन में दो कमियां हैं: काफी अपर्याप्त: टन का गुणन और घातांक, बार-बार एक ही शक्तियों को गुणा करना आदि। Pythonic, दिखता है। लेकिन मुझे नहीं लगता कि पायथन प्रदर्शन को मारने के बारे में है। समस्या दो: भाजक क्रम में वापस नहीं आए हैं।
टॉमस गैंडर

34

शिमि ने जो कहा है, उस पर विस्तार करने के लिए, आपको केवल 1 से वर्गमूल n तक अपना लूप चलाना चाहिए। फिर जोड़ी को खोजने के लिए, करो n / i, और यह पूरी समस्या स्थान को कवर करेगा।

जैसा कि यह भी उल्लेख किया गया था, यह एक एनपी, या 'मुश्किल' समस्या है। थकाऊ खोज, जिस तरह से आप कर रहे हैं, यह उतने ही अच्छे हैं जितना कि यह गारंटीशुदा उत्तरों के लिए मिलता है। इस तथ्य का उपयोग एन्क्रिप्शन एल्गोरिदम और उन्हें सुरक्षित करने में मदद करने के लिए किया जाता है। यदि कोई इस समस्या को हल करने के लिए था, तो सबसे ज्यादा अगर हमारे सभी मौजूदा 'सुरक्षित' संचार असुरक्षित नहीं होंगे।

पायथन कोड:

import math

def divisorGenerator(n):
    large_divisors = []
    for i in xrange(1, int(math.sqrt(n) + 1)):
        if n % i == 0:
            yield i
            if i*i != n:
                large_divisors.append(n / i)
    for divisor in reversed(large_divisors):
        yield divisor

print list(divisorGenerator(100))

जो एक सूची की तरह उत्पादन करना चाहिए:

[१, २, ४, ५, १०, २०, २५, ५०, १००]

2
क्योंकि, जब आपके पास 1..10 के बीच तत्वों की एक सूची है, तो आप 11..100 तुच्छ के बीच किसी भी तत्व को उत्पन्न कर सकते हैं। आपको {1, 2, 4, 5, 10} मिलता है। इन तत्वों में से प्रत्येक को 100 से विभाजित करें और आप {100, 50, 20, 25, 10}।
मैथ्यू शारले

2
कारक हमेशा युग्म में उत्पन्न होते हैं, परिभाषा के आधार पर। केवल sqrt (n) में खोज कर, आप एक शक्ति 2 से अपना काम काट रहे हैं
मैथ्यू शारले

यह मेरी पोस्ट के संस्करण की तुलना में बहुत तेज़ है, लेकिन यह अभी भी प्रधानमंत्री कारकों का उपयोग करने वाले संस्करण की तुलना में बहुत धीमा है
एंड्रिया अंबू

मैं मानता हूं कि यह सबसे अच्छा समाधान नहीं है। मैं केवल 'गूंगा' खोज करने के एक 'बेहतर' तरीके की ओर इशारा कर रहा था जो पहले से ही समय की बचत करेगा।
मैथ्यू शार्ले

फैक्टराइजेशन को एनपी-हार्ड नहीं दिखाया गया है। en.wikipedia.org/wiki/Integer_factorization और समस्या यह थी कि दिए गए सभी विभाजकों को खोजने के लिए कि प्रमुख कारक (कठिन भाग) पहले ही मिल चुके थे।
जेमी

19

हालाँकि इसके पहले से ही कई समाधान हैं, मुझे वास्तव में यह पोस्ट करना है :)

यह एक है:

  • पठनीय
  • कम
  • आत्म निहित, कॉपी और पेस्ट तैयार
  • त्वरित (कई प्रमुख कारकों और भाजक के मामलों में,> स्वीकृत समाधान की तुलना में 10 गुना तेज)
  • python3, python2 और pypy आज्ञाकारी

कोड:

def divisors(n):
    # get factors and their counts
    factors = {}
    nn = n
    i = 2
    while i*i <= nn:
        while nn % i == 0:
            factors[i] = factors.get(i, 0) + 1
            nn //= i
        i += 1
    if nn > 1:
        factors[nn] = factors.get(nn, 0) + 1

    primes = list(factors.keys())

    # generates factors from primes[k:] subset
    def generate(k):
        if k == len(primes):
            yield 1
        else:
            rest = generate(k+1)
            prime = primes[k]
            for factor in rest:
                prime_to_i = 1
                # prime_to_i iterates prime**i values, i being all possible exponents
                for _ in range(factors[prime] + 1):
                    yield factor * prime_to_i
                    prime_to_i *= prime

    # in python3, `yield from generate(0)` would also work
    for factor in generate(0):
        yield factor

मैं जगह लेंगे while i*i <= nnद्वारा while i <= limit, जहांlimit = math.sqrt(n)
Rafa0809

17

मुझे लगता है कि आप math.sqrt(n)n / 2 के बजाय रुक सकते हैं ।

मैं आपको उदाहरण दूंगा ताकि आप इसे आसानी से समझ सकें। अब sqrt(28)है 5.29तो ceil(5.29)हो सकता है 6. तो मैं अगर मैं 6 में बंद हो तो मैं सब divisors प्राप्त कर सकते हैं करेंगे। कैसे?

पहले कोड देखें और फिर छवि देखें:

import math
def divisors(n):
    divs = [1]
    for i in xrange(2,int(math.sqrt(n))+1):
        if n%i == 0:
            divs.extend([i,n/i])
    divs.extend([n])
    return list(set(divs))

अब, नीचे दी गई छवि देखें:

चलो का कहना है कि मैं पहले से ही जोड़ लिया है 1मेरी divisors सूची में है और मैं के साथ शुरू i=2तो

एक 28 के भाजक

इसलिए सभी पुनरावृत्तियों के अंत में, क्योंकि मैंने अपनी सूची में भागफल और भाजक को जोड़ दिया है, 28 के सभी भाजक आबाद हैं।

स्रोत: संख्या के विभाजकों का निर्धारण कैसे करें


2
अच्छा अच्छा!! math.sqrt(n) instead of n/2लालित्य के लिए अनिवार्य है
Rafa0809

यह गलत है। आप भूल गए हैं n अपने आप से विभाज्य है।
जस्सोनलोंहार्ड

1
अच्छा उत्तर। सरल और स्पष्ट। लेकिन अजगर 3 के लिए 2 आवश्यक परिवर्तन हैं: n / i को int (n / i) कारण n / i का उपयोग करके टाइप किया जाना चाहिए / फ्लोट संख्या पैदा करता है। इसके अलावा रेंजएक्स को अजगर 3 में पदावनत किया गया है और रेंज द्वारा प्रतिस्थापित किया जा रहा है।
जियोफॉय कैला

7

मुझे ग्रेग समाधान पसंद है, लेकिन मुझे लगता है कि यह अधिक अजगर की तरह था। मुझे लगता है कि यह तेज और अधिक पठनीय होगा; इसलिए कोडिंग के कुछ समय बाद मैं इसके साथ बाहर आया।

सूचियों के कार्टेशियन उत्पाद बनाने के लिए पहले दो कार्यों की आवश्यकता होती है। और इस समस्या के उत्पन्न होने पर पुन: उपयोग किया जा सकता है। वैसे, मुझे खुद ही यह प्रोग्राम करना था, अगर किसी को इस समस्या के लिए मानक समाधान का पता है, तो कृपया मुझसे संपर्क करने के लिए स्वतंत्र महसूस करें।

"Factorgenerator" अब एक शब्दकोश देता है। और फिर डिक्शनरी को "डिवाइडर" में खिलाया जाता है, जो इसका उपयोग सूचियों की पहली सूची तैयार करने के लिए करता है, जहां प्रत्येक सूची में p p के साथ फॉर्म p ^ n के कारकों की सूची है। फिर हम उन सूचियों के कार्टेशियन उत्पाद बनाते हैं, और हम अंत में भाजक के समाधान के लिए ग्रेग के समाधान का उपयोग करते हैं। हम उन्हें सॉर्ट करते हैं, और उन्हें वापस करते हैं।

मैंने इसका परीक्षण किया और यह पिछले संस्करण की तुलना में थोड़ा तेज़ प्रतीत होता है। मैंने इसे एक बड़े कार्यक्रम के हिस्से के रूप में परीक्षण किया, इसलिए मैं वास्तव में यह नहीं कह सकता कि यह कितना तेज़ है।

पिएत्रो स्पेरोनी (pietrosperoni dot it)

from math import sqrt


##############################################################
### cartesian product of lists ##################################
##############################################################

def appendEs2Sequences(sequences,es):
    result=[]
    if not sequences:
        for e in es:
            result.append([e])
    else:
        for e in es:
            result+=[seq+[e] for seq in sequences]
    return result


def cartesianproduct(lists):
    """
    given a list of lists,
    returns all the possible combinations taking one element from each list
    The list does not have to be of equal length
    """
    return reduce(appendEs2Sequences,lists,[])

##############################################################
### prime factors of a natural ##################################
##############################################################

def primefactors(n):
    '''lists prime factors, from greatest to smallest'''  
    i = 2
    while i<=sqrt(n):
        if n%i==0:
            l = primefactors(n/i)
            l.append(i)
            return l
        i+=1
    return [n]      # n is prime


##############################################################
### factorization of a natural ##################################
##############################################################

def factorGenerator(n):
    p = primefactors(n)
    factors={}
    for p1 in p:
        try:
            factors[p1]+=1
        except KeyError:
            factors[p1]=1
    return factors

def divisors(n):
    factors = factorGenerator(n)
    divisors=[]
    listexponents=[map(lambda x:k**x,range(0,factors[k]+1)) for k in factors.keys()]
    listfactors=cartesianproduct(listexponents)
    for f in listfactors:
        divisors.append(reduce(lambda x, y: x*y, f, 1))
    divisors.sort()
    return divisors



print divisors(60668796879)

पुनश्च यह पहली बार है जब मैं स्टैकओवरफ्लो में पोस्ट कर रहा हूं। मैं किसी भी प्रतिक्रिया के लिए आगे देख रहा हूं।


Python 2.6 में एक itertools.product () है।
jfs

एक संस्करण जो सूची के बजाय जनरेटर का उपयोग करता है। हर जगह क्लीनर साफ हो सकता है।
jfs

एरेटोस्थेनेज की चलनी से कम रूढ़ अंक उत्पन्न करने के लिए या बराबर sqrt (एन) इस्तेमाल किया जा सकता stackoverflow.com/questions/188425/project-euler-problem#193605
JFS

1
कोडिंग शैली: घातांक = [k ** x k में k, v के लिए कारकों में () (x + के लिए रेंज में) (v + 1)]
jfs

सूचीप्राप्ति के लिए: [[k ** x के लिए x रेंज में (v + 1)] के लिए k, v में v। कारकों ())
klenwell

3

यहाँ शुद्ध पायथन 3.6 में 10 ** 16 तक की संख्या के लिए एक स्मार्ट और तेज़ तरीका है,

from itertools import compress

def primes(n):
    """ Returns  a list of primes < n for n > 2 """
    sieve = bytearray([True]) * (n//2)
    for i in range(3,int(n**0.5)+1,2):
        if sieve[i//2]:
            sieve[i*i//2::i] = bytearray((n-i*i-1)//(2*i)+1)
    return [2,*compress(range(3,n,2), sieve[1:])]

def factorization(n):
    """ Returns a list of the prime factorization of n """
    pf = []
    for p in primeslist:
      if p*p > n : break
      count = 0
      while not n % p:
        n //= p
        count += 1
      if count > 0: pf.append((p, count))
    if n > 1: pf.append((n, 1))
    return pf

def divisors(n):
    """ Returns an unsorted list of the divisors of n """
    divs = [1]
    for p, e in factorization(n):
        divs += [x*p**k for k in range(1,e+1) for x in divs]
    return divs

n = 600851475143
primeslist = primes(int(n**0.5)+1) 
print(divisors(n))

व्हाट्सएप एल्गोरिथ्म के नाम का इस्तेमाल प्राइमस खोजने और फैक्ट करने के लिए किया जाता है? क्योंकि मैं इसे C # ..
Kyu96

2

CodeReview से अनुकूलित , यहाँ एक संस्करण है जो साथ काम करता है num=1!

from itertools import product
import operator

def prod(ls):
   return reduce(operator.mul, ls, 1)

def powered(factors, powers):
   return prod(f**p for (f,p) in zip(factors, powers))


def divisors(num) :

   pf = dict(prime_factors(num))
   primes = pf.keys()
   #For each prime, possible exponents
   exponents = [range(i+1) for i in pf.values()]
   return (powered(primes,es) for es in product(*exponents))

1
मैं एक त्रुटि हो रही हो रहे हैं: NameError: global name 'prime_factors' is not defined। अन्य उत्तरों में से कोई भी, और न ही मूल प्रश्न, यह परिभाषित करता है कि यह क्या करता है।
अन्नपूर्णे

2

मैं सिर्फ भविष्य के संदर्भ के लिए अनिवर्थ के थोड़े संशोधित संस्करण को जोड़ने जा रहा हूं (जैसा कि मेरा मानना ​​है कि यह सबसे अधिक पायथोनिक है)।

from math import sqrt

def divisors(n):
    divs = {1,n}
    for i in range(2,int(sqrt(n))+1):
        if n%i == 0:
            divs.update((i,n//i))
    return divs

1

पुराना सवाल है, लेकिन यहाँ मेरा लेना है:

def divs(n, m):
    if m == 1: return [1]
    if n % m == 0: return [m] + divs(n, m - 1)
    return divs(n, m - 1)

आप इसके साथ प्रॉक्सी कर सकते हैं:

def divisorGenerator(n):
    for x in reversed(divs(n, n)):
        yield x

नोट: समर्थन करने वाली भाषाओं के लिए, यह पुनरावर्ती हो सकता है।


0

यह मानते हुए कि factorsफ़ंक्शन n के कारकों को लौटाता है (उदाहरण के लिए, factors(60)सूची [2, 2, 3, 5]) लौटाता है, यहाँ n के विभाजकों की गणना करने के लिए एक फ़ंक्शन है :

function divisors(n)
    divs := [1]
    for fact in factors(n)
        temp := []
        for div in divs
            if fact * div not in divs
                append fact * div to temp
        divs := divs + temp
    return divs

क्या वह अजगर है? वैसे भी, यह निश्चित रूप से अजगर 3.x नहीं है।
गिन्किन

यह स्यूडोकोड है, जिसे अजगर में अनुवाद करने के लिए सरल होना चाहिए।
user448810

3 साल देर से, कभी भी देर से बेहतर :) IMO, ऐसा करने के लिए यह सबसे सरल, सबसे छोटा कोड है। मेरे पास तुलना तालिका नहीं है, लेकिन मैं अपने i5 पोर्टेबल लैपटॉप पर 1s में दस लाख तक के विभाजकों की गणना और गणना कर सकता हूं।
रियाज मंसूर

0

यहाँ मेरा समाधान है। यह गूंगा लगता है, लेकिन अच्छी तरह से काम करता है ... और मैं सभी उचित विभाजक खोजने की कोशिश कर रहा था, इसलिए लूप की शुरुआत i = 2 से हुई।

import math as m 

def findfac(n):
    faclist = [1]
    for i in range(2, int(m.sqrt(n) + 2)):
        if n%i == 0:
            if i not in faclist:
                faclist.append(i)
                if n/i not in faclist:
                    faclist.append(n/i)
    return facts

टाइपो: वापसी के तथ्य => वापसी की सूचना
जोनाथ पी।

0

यदि आप केवल सूची समझ का उपयोग करने के बारे में परवाह करते हैं और आपके लिए कुछ और मायने नहीं रखता है!

from itertools import combinations
from functools import reduce

def get_devisors(n):
    f = [f for f,e in list(factorGenerator(n)) for i in range(e)]
    fc = [x for l in range(len(f)+1) for x in combinations(f, l)]
    devisors = [1 if c==() else reduce((lambda x, y: x * y), c) for c in set(fc)]
    return sorted(devisors)

0

यदि आपके पीसी में टन मेमोरी है, तो एक ब्रूट सिंगल लाइन पर्याप्त तेजी से सुन्न हो सकती है:

N = 10000000; tst = np.arange(1, N); tst[np.mod(N, tst) == 0]
Out: 
array([      1,       2,       4,       5,       8,      10,      16,
            20,      25,      32,      40,      50,      64,      80,
           100,     125,     128,     160,     200,     250,     320,
           400,     500,     625,     640,     800,    1000,    1250,
          1600,    2000,    2500,    3125,    3200,    4000,    5000,
          6250,    8000,   10000,   12500,   15625,   16000,   20000,
         25000,   31250,   40000,   50000,   62500,   78125,   80000,
        100000,  125000,  156250,  200000,  250000,  312500,  400000,
        500000,  625000, 1000000, 1250000, 2000000, 2500000, 5000000])

मेरे धीमे पीसी पर 1s से कम लेता है।


0

जनरेटर फ़ंक्शन के माध्यम से मेरा समाधान है:

def divisor(num):
    for x in range(1, num + 1):
        if num % x == 0:
            yield x
    while True:
        yield None

-1
return [x for x in range(n+1) if n/x==int(n/x)]

3
प्रश्नकर्ता ने बेहतर एल्गोरिथ्म के लिए कहा, न कि केवल एक प्रारंभिक प्रारूप।
विड्रैक

4
आपको शून्य से विभाजन से बचने के लिए रेंज (1, n + 1) का उपयोग करने की आवश्यकता है। इसके अलावा, आपको पहले विभाजन के लिए फ्लोट (एन) का उपयोग करने की आवश्यकता है यदि पायथन 2.7 का उपयोग कर रहे हैं, तो यहां 1/2 = 0
जेन्स मुंक

-1

मेरे लिए यह ठीक काम करता है और साफ भी है (पायथन 3)

def divisors(number):
    n = 1
    while(n<number):
        if(number%n==0):
            print(n)
        else:
            pass
        n += 1
    print(number)

यदि आप चाहते हैं तो बहुत तेज़ नहीं है, लेकिन लाइन से विभाजक रेखा लौटाता है, अगर आप वास्तव में चाहते हैं तो आप list.append (n) और list.append (संख्या) कर सकते हैं

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.