อัลกอริทึมในการค้นหาตัวประกอบสำคัญที่สุดของตัวเลข


183

วิธีที่ดีที่สุดในการคำนวณปัจจัยหลักที่ใหญ่ที่สุดของจำนวนคืออะไร?

ฉันคิดว่ามีประสิทธิภาพมากที่สุดจะเป็นดังต่อไปนี้:

  1. ค้นหาจำนวนเฉพาะต่ำสุดที่หารได้อย่างหมดจด
  2. ตรวจสอบว่าผลลัพธ์ของการหารเป็นเรื่องสำคัญหรือไม่
  3. ถ้าไม่พบต่อไปต่ำสุด
  4. ไปที่ 2

ฉันคิดว่ามันง่ายกว่าที่จะคำนวณปัจจัยสำคัญเล็ก ๆ มันเกี่ยวกับใช่มั้ย ฉันควรมองหาวิธีอื่นใด

แก้ไข: ตอนนี้ฉันรู้แล้วว่าวิธีการของฉันไร้ประโยชน์หากมีมากกว่า 2 ปัจจัยหลักในการเล่นตั้งแต่ขั้นตอนที่ 2 ล้มเหลวเมื่อผลลัพธ์เป็นผลงานของสองช่วงเวลาอื่นดังนั้นจึงจำเป็นต้องมีขั้นตอนวิธีแบบเรียกซ้ำ

แก้ไขอีกครั้ง: และตอนนี้ฉันรู้แล้วว่าวิธีนี้ยังใช้งานได้เพราะตัวเลขสำคัญที่พบล่าสุดจะต้องเป็นเลขที่สูงที่สุดดังนั้นการทดสอบเพิ่มเติมเกี่ยวกับผลลัพธ์ที่ไม่ได้เป็นนายกจากขั้นตอนที่ 2 จะส่งผลให้นายกที่เล็กลง


แนวทางของฉันคือ: (1) หารจำนวนมากได้ 2 ด้วย; (2) ตรวจสอบว่าจำนวนมากแบ่งเท่า ๆ กันหรือไม่ (3) ถ้าเป็นเช่นนั้นตรวจสอบว่าหารด้วย 2 จำนวนนั้นเป็นจำนวนเฉพาะหรือไม่ หากเป็นเช่นนั้นให้ส่งคืน (4) อื่น, ลบ 1 จากหารด้วย 2 จำนวน, กลับสู่ขั้นตอนที่ 3
Kevin Meredith

1.หาจำนวนใด ๆ ที่แบ่งอย่างชัดเจน (สำหรับ i = 2 ถึง int (sqr (NUM))) 2.หารด้วยตัวเลขนั้น (num = num / i) และเกิดขึ้นอีกจนกว่าจะไม่พบสิ่งใดใน1.ช่วงเวลา3. numเป็นปัจจัยที่ใหญ่ที่สุด
user3819867

1
เราสามารถหารด้วยจำนวนเฉพาะน้อยและสิ่งที่เหลืออยู่ในที่สุดก็คือปัจจัยสำคัญที่ใหญ่ที่สุด (ฉันเดา)

คำตอบ:


134

จริงๆแล้วมีหลายวิธีที่มีประสิทธิภาพมากขึ้นในการค้นหาปัจจัยของตัวเลขขนาดใหญ่ (สำหรับแผนกทดลองที่เล็กกว่าทำงานได้ดีพอสมควร)

วิธีการหนึ่งซึ่งเป็นไปอย่างรวดเร็วมากถ้าจำนวนการป้อนข้อมูลที่มีปัจจัยทั้งสองอย่างใกล้ชิดกับรากของมันเป็นที่รู้จักกันแฟร์มาต์ factorisation มันทำให้การใช้งานของเอกลักษณ์ N = (a + b) (a - b) = a ^ 2 - b ^ 2 และง่ายต่อการเข้าใจและนำไปใช้ น่าเสียดายที่มันไม่เร็วโดยทั่วไป

วิธีที่รู้จักกันดีที่สุดสำหรับหมายเลขแฟถึง 100 ตัวเลขยาวเป็นตะแกรงกำลังสอง โบนัสเป็นส่วนหนึ่งของอัลกอริทึมที่ทำได้ง่ายด้วยการประมวลผลแบบขนาน

แต่ขั้นตอนวิธีการอื่นที่ผมเคยได้ยินเป็นอัลกอริทึมของโรพอลลาร์ มันไม่ได้มีประสิทธิภาพเทียบเท่ากับ Quadratic Sieve โดยทั่วไป แต่ดูเหมือนจะง่ายกว่าในการนำไปใช้


เมื่อคุณตัดสินใจที่จะแยกตัวเลขออกเป็นสองปัจจัยแล้วนี่คืออัลกอริทึมที่เร็วที่สุดที่ฉันสามารถนึกได้ในการค้นหาตัวประกอบสำคัญที่สุดของตัวเลข:

สร้างคิวลำดับความสำคัญซึ่งเก็บหมายเลขไว้ในตอนแรก การวนซ้ำแต่ละครั้งคุณลบจำนวนสูงสุดออกจากคิวและพยายามแยกออกเป็นสองปัจจัย (ไม่อนุญาตให้ 1 เป็นหนึ่งในปัจจัยเหล่านั้นแน่นอน) หากขั้นตอนนี้ล้มเหลวจำนวนนั้นเป็นจำนวนเฉพาะและคุณมีคำตอบ! มิฉะนั้นคุณจะเพิ่มสองปัจจัยลงในคิวและทำซ้ำ


3
พอลลาร์โดโรและวิธีเส้นโค้งรูปไข่จะดีกว่ามากในการกำจัดปัจจัยสำคัญขนาดเล็กจำนวนของคุณกว่าตะแกรงกำลังสอง คำพูดคำจามีเกี่ยวกับรันไทม์เดียวกันไม่ว่าจำนวน วิธีการใดที่เร็วกว่านั้นขึ้นอยู่กับหมายเลขของคุณ คำพูดคำจาจะแตกจำนวนตัวประกอบที่ยากขึ้นเร็วขึ้นในขณะที่ rho และ ECM จะแตกตัวตัวประกอบที่ง่ายขึ้นให้เร็วขึ้น
tmyklebu

ขอขอบคุณสำหรับข้อเสนอแนะการเปลี่ยนแปลงแบบสมการกำลังสอง ฉันต้องใช้สิ่งนี้กับลูกค้าของฉันเวอร์ชันแรกที่ฉันพบคือบางสิ่งตามที่ @mercutio แนะนำในคำถามของเขา วิธีการแก้ปัญหากำลังสองคือสิ่งที่จะเปิดเครื่องเครื่องมือที่ลูกค้าของฉันตอนนี้math.tools/calculator/prime-factors
dors

หากมีวิธีที่มีประสิทธิภาพในการแก้ปัญหานี้แสดงว่าการเข้ารหัสเว็บไม่ปลอดภัยหรือไม่
BKSpurgeon

141

นี่เป็นอัลกอริทึมที่ดีที่สุดที่ฉันรู้จัก (ใน Python)

def prime_factors(n):
    """Returns all the prime factors of a positive integer"""
    factors = []
    d = 2
    while n > 1:
        while n % d == 0:
            factors.append(d)
            n /= d
        d = d + 1

    return factors


pfs = prime_factors(1000)
largest_prime_factor = max(pfs) # The largest element in the prime factor list

วิธีการข้างต้นทำงานในO(n)กรณีที่เลวร้ายที่สุด (เมื่อการป้อนข้อมูลเป็นจำนวนเฉพาะ)

แก้ไข:
ด้านล่างนี้เป็นO(sqrt(n))รุ่นตามที่แนะนำในความคิดเห็น นี่คือรหัสอีกครั้ง

def prime_factors(n):
    """Returns all the prime factors of a positive integer"""
    factors = []
    d = 2
    while n > 1:
        while n % d == 0:
            factors.append(d)
            n /= d
        d = d + 1
        if d*d > n:
            if n > 1: factors.append(n)
            break
    return factors


pfs = prime_factors(1000)
largest_prime_factor = max(pfs) # The largest element in the prime factor list

11
โปรดอ่านและ / หรือเรียกใช้รหัสนี้ก่อนที่จะลงคะแนน มันใช้งานได้ดี เพียงคัดลอกและวาง ตามที่เขียนไว้แล้ว prime_factors (1,000) จะส่งคืน [2,2,2,5,5,5] ซึ่งควรตีความว่าเป็น 2 ^ 3 * 5 ^ 3 ซึ่งเป็นตัวประกอบที่สำคัญ
Triptych

11
"ทำงานในO(sqrt(n))กรณีที่เลวร้ายที่สุด" - ไม่มันทำงานในO(n)กรณีที่เลวร้ายที่สุด (เช่นเมื่อnนายก)
Sheldon L. Cooper

16
ง่ายที่จะทำให้มันเป็น O (sqrt (n)) คุณเพียงแค่หยุดลูปเมื่อ d * d> n และถ้า n> 1 ณ จุดนี้ค่าของมันควรจะผนวกเข้ากับรายการของปัจจัยสำคัญ
Sumudu Fernando

5
มีชื่อนี้ไหม
ทำนาย

11
เนื่องจาก 2 เป็นเลขเฉพาะคู่เท่านั้นดังนั้นแทนที่จะเพิ่ม 1 ในแต่ละครั้งคุณสามารถวนซ้ำแยกกันสำหรับ d = 2 แล้วเพิ่มขึ้นทีละ 1 และจาก d = 3 เป็นต้นไปคุณสามารถเพิ่มได้ 2 ดังนั้นมันจะลดจำนวนลง ของการทำซ้ำ ... :)
tailor_raj

18

คำตอบของฉันขึ้นอยู่กับTriptychแต่ปรับปรุงให้ดีขึ้นเยอะ มันขึ้นอยู่กับข้อเท็จจริงที่ว่าเกิน 2 และ 3 ตัวเลขสำคัญทั้งหมดจะอยู่ในรูปแบบ 6n-1 หรือ 6n + 1

var largestPrimeFactor;
if(n mod 2 == 0)
{
    largestPrimeFactor = 2;
    n = n / 2 while(n mod 2 == 0);
}
if(n mod 3 == 0)
{
    largestPrimeFactor = 3;
    n = n / 3 while(n mod 3 == 0);
}

multOfSix = 6;
while(multOfSix - 1 <= n)
{
    if(n mod (multOfSix - 1) == 0)
    {
        largestPrimeFactor = multOfSix - 1;
        n = n / largestPrimeFactor while(n mod largestPrimeFactor == 0);
    }

    if(n mod (multOfSix + 1) == 0)
    {
        largestPrimeFactor = multOfSix + 1;
        n = n / largestPrimeFactor while(n mod largestPrimeFactor == 0);
    }
    multOfSix += 6;
}

ฉันเพิ่งเขียนบทความบล็อกที่อธิบายวิธีการทำงานของอัลกอริทึมนี้

ฉันจะลองใช้วิธีที่ไม่จำเป็นต้องทำการทดสอบแบบดั้งเดิม (และไม่มีการสร้างตะแกรง) จะทำงานได้เร็วกว่าวิธีที่ใช้วิธีนั้น หากเป็นกรณีนี้อาจเป็นวิธีที่เร็วที่สุดที่นี่


12
คุณสามารถนำความคิดนี้ไปให้ไกลกว่านั้นอีกเช่นเกิน 2,3,5 ช่วงเวลาทั้งหมดอยู่ในรูปแบบ 30n + k (n> = 0) โดยที่ k ใช้ค่าเหล่านั้นระหว่าง 1 ถึง 29 เท่านั้นซึ่งไม่สามารถหารด้วย 2,3 หรือ 5 คือ 7,11,13,17,19,23,29 คุณสามารถปรับตัวเองแบบไดนามิกได้หลังจากทุกช่วงเวลาที่คุณพบจนถึง 2 * 3 * 5 * 7 * ... * n + k โดยที่ k ต้องไม่หารด้วยจำนวนเฉพาะเหล่านี้ (โปรดทราบว่าไม่จำเป็นต้องเป็นไปได้ทั้งหมด k เป็นนายกเช่นสำหรับ 210n + k คุณต้องรวม 121 มิฉะนั้นคุณจะพลาด331 )
โทเบียส Kienzler

2
ฉันเดาว่ามันควรจะเป็นwhile (multOfSix - 1 <= n)
Nader Ghanbari

8

รหัส JavaScript:

'option strict';

function largestPrimeFactor(val, divisor = 2) { 
    let square = (val) => Math.pow(val, 2);

    while ((val % divisor) != 0 && square(divisor) <= val) {
        divisor++;
    }

    return square(divisor) <= val
        ? largestPrimeFactor(val / divisor, divisor)
        : val;
}

ตัวอย่างการใช้งาน:

let result = largestPrimeFactor(600851475143);

นี่คือตัวอย่างของรหัส :


7

คล้ายกับคำตอบ @Triptych แต่ก็แตกต่างกัน ในรายการตัวอย่างหรือพจนานุกรมนี้ไม่ได้ใช้ รหัสเขียนใน Ruby

def largest_prime_factor(number)
  i = 2
  while number > 1
    if number % i == 0
      number /= i;
    else
      i += 1
    end
  end
  return i
end

largest_prime_factor(600851475143)
# => 6857

ในที่สุดสิ่งที่อ่านได้และทันที (ใน js) ปฏิบัติการในเวลาเดียวกัน ฉันพยายามใช้รายการที่ไม่มีที่สิ้นสุดและมันก็ช้าเกินไปที่ 1 ล้าน
Ebuall

4

ตัวเลขทั้งหมดสามารถแสดงเป็นผลคูณของช่วงเวลาเช่น:

102 = 2 x 3 x 17
712 = 2 x 2 x 2 x 89

คุณสามารถค้นหาสิ่งเหล่านี้ได้โดยเริ่มต้นที่ 2 และแบ่งต่อไปเรื่อย ๆ จนกว่าผลลัพธ์จะไม่เป็นจำนวนของคุณ:

712 / 2 = 356 .. 356 / 2 = 178 .. 178 / 2 = 89 .. 89 / 89 = 1

การใช้วิธีนี้คุณไม่จำเป็นต้องคำนวณช่วงเวลาใด ๆ : พวกเขาทั้งหมดจะเป็นช่วงเวลาที่กำหนดขึ้นอยู่กับความจริงที่ว่าคุณได้แยกจำนวนมากที่สุดเท่าที่เป็นไปได้กับตัวเลขก่อนหน้านี้ทั้งหมด

number = 712;
currNum = number;    // the value we'll actually be working with
for (currFactor in 2 .. number) {
    while (currNum % currFactor == 0) {
        // keep on dividing by this number until we can divide no more!
        currNum = currNum / currFactor     // reduce the currNum
    }
    if (currNum == 1) return currFactor;    // once it hits 1, we're done.
}

ใช่ แต่นี่ไม่มีประสิทธิภาพอย่างน่ากลัว เมื่อคุณแบ่ง 2s ออกแล้วคุณไม่ควรลองหารด้วย 4 หรือ 6 หรือ 6 หรือ ... ; มันมีประสิทธิภาพมากขึ้นในการตรวจสอบเฉพาะช่วงเวลาหรือใช้อัลกอริทึม toher
wnoise

6
+1 เพื่อชดเชย wnoise ที่ฉันคิดว่าผิด การพยายามหารด้วย 4 จะเกิดขึ้นเพียงครั้งเดียวและจะล้มเหลวทันที ฉันไม่คิดว่ามันจะแย่ไปกว่าการลบ 4 ออกจากรายชื่อผู้สมัครบางส่วนและมันเร็วกว่าการค้นหาช่วงเวลาก่อนหน้าทั้งหมด
Triptych

2
@Beowulf ลองใช้รหัสนี้ก่อนลงคะแนน มันส่งกลับปัจจัยสำคัญ คุณไม่เข้าใจอัลกอริทึม
Triptych

3
รหัสทำงานได้ดี แต่ช้าถ้าหมายเลขที่เข้ามาเป็นจำนวนเฉพาะ ฉันจะวิ่งขึ้นไปที่จตุรัสและเพิ่มทีละ 2 เท่านั้นมันอาจจะช้าเกินไปสำหรับคนจำนวนมาก
blabla999

4
blabla999 ถูกต้องแน่นอน ตัวอย่างคือ 1234567898766700 = 2 * 2 * 5 * 5 * 12345678987667 เมื่อเราไปถึงcurrFactor = 3513642เรารู้ว่า 12345678987667 นั้นดีเลิศและควรส่งคืนเป็นคำตอบ แต่รหัสนี้จะดำเนินการแจงนับต่อไปจนถึง 12345678987667 นั่นคือ 3,513,642x ช้ากว่าที่จำเป็น
Will Ness

4
    //this method skips unnecessary trial divisions and makes 
    //trial division more feasible for finding large primes

    public static void main(String[] args) 
    {
        long n= 1000000000039L; //this is a large prime number 
        long i = 2L;
        int test = 0;

        while (n > 1)
        {
            while (n % i == 0)
            {
                n /= i;     
            }

            i++;

            if(i*i > n && n > 1) 
            {
                System.out.println(n); //prints n if it's prime
                test = 1;
                break;
            }
        }

        if (test == 0)  
            System.out.println(i-1); //prints n if it's the largest prime factor
    }

1
คุณลองรหัสของคุณด้วย 1,000,000,000,039 หรือยัง มันควรวิ่งในพริบตาด้วย ทำมัน?
Will Ness

2
คุณสามารถรู้ล่วงหน้าได้โดยไม่ต้องลอง 10 ^ 12 = (2 * 5) ^ 12 = 2 ^ 12 * 5 ^ 12 ดังนั้นคุณwhileห่วงจะไปถึงค่านิยมของi 2,2,2,2,2,2,2,2,2,2,2,2, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5, 2,3,4,5ทำซ้ำทั้งหมด 60 รายการ แต่สำหรับ (10 ^ 12 + 39) จะมี (10 ^ 12 + 38) i=2,3,4,5,6,...,10^12+39การทำซ้ำ แม้ว่า 10 ^ 10 ops ใช้เวลาหนึ่งวินาที 10 ^ 12 จะใช้เวลา 100 วินาที แต่ต้องการการทำซ้ำ 10 ^ 6 เท่านั้นและถ้า 10 ^ 10 ops ใช้เวลาที่สอง 10 ^ 6 จะใช้เวลา 1 / 10,000th ของวินาที
Will Ness

1
เพราะฉันไม่รู้ (10 ^ 12 + 39) เป็นหมายเลขเฉพาะที่ฉันทำตอนนี้ ฉันได้สิ่งที่คุณพูด
the_prole

1
ตกลงเพื่อให้คุณสามารถเปลี่ยนรหัสของคุณเพื่อที่จะไม่มีการชะลอตัวครั้งใหญ่สำหรับช่วงเวลา: หาก n = a b และ <= b ดังนั้น a <= b a = n คือ a <= n . และถ้าเราไปถึง +1, n ก็แน่นอน (ping ฉันถ้าคุณแก้ไขคำตอบของคุณเพื่อรวมสิ่งนี้)
Will Ness

1
เกิดอะไรขึ้นเมื่อlong n = 2*1000000000039L? ใช้งานได้เร็วเท่าที่ควรหรือไม่ (และคุณสามารถทำให้รหัสของคุณง่ายขึ้นโดยใช้return;คำสั่งได้หรือไม่) (ถ้าคุณต้องการให้ฉันหยุดสะกิดคุณเพียงแค่พูดอย่างนั้น;)
Will Ness

4

ทางออกที่ง่ายที่สุดคือฟังก์ชั่นแบบเรียกซ้ำซึ่งกันและกัน

ฟังก์ชั่นแรกสร้างหมายเลขเฉพาะทั้งหมด:

  1. เริ่มต้นด้วยรายการหมายเลขธรรมชาติทั้งหมดที่มากกว่า 1
  2. ลบตัวเลขทั้งหมดที่ไม่ได้สำคัญ นั่นคือตัวเลขที่ไม่มีปัจจัยสำคัญ (นอกเหนือจากตัวเอง) ดูด้านล่าง

ฟังก์ชั่นที่สองส่งกลับปัจจัยสำคัญของจำนวนที่กำหนดnในการสั่งซื้อที่เพิ่มขึ้น

  1. ทำรายการช่วงเวลาทั้งหมด (ดูด้านบน)
  2. nนำตัวเลขทั้งหมดที่ไม่ได้เป็นปัจจัย

ตัวประกอบสำคัญที่สุดของnคือจำนวนสุดท้ายที่กำหนดโดยฟังก์ชันที่สอง

อัลกอริทึมนี้ต้องมีรายการที่ขี้เกียจหรือภาษา (หรือโครงสร้างข้อมูล) ที่มีความหมายการโทรตามความต้องการ

สำหรับการชี้แจงนี่คือการดำเนินการหนึ่ง (ไม่มีประสิทธิภาพ) ด้านบนใน Haskell:

import Control.Monad

-- All the primes
primes = 2 : filter (ap (<=) (head . primeFactors)) [3,5..]

-- Gives the prime factors of its argument
primeFactors = factor primes
  where factor [] n = []
        factor xs@(p:ps) n =
          if p*p > n then [n]
          else let (d,r) = divMod n p in
            if r == 0 then p : factor xs d
            else factor ps n

-- Gives the largest prime factor of its argument
largestFactor = last . primeFactors

การทำให้สิ่งนี้เร็วขึ้นนั้นเป็นเพียงเรื่องของความชาญฉลาดมากขึ้นเกี่ยวกับการตรวจจับว่าตัวเลขใดเป็นตัวประกอบและ / หรือปัจจัยnแต่อัลกอริทึมยังคงเหมือนเดิม


2
n = abs(number);
result = 1;
if (n mod 2 == 0) {
  result = 2;
  while (n mod 2 = 0) n /= 2;
}
for(i=3; i<sqrt(n); i+=2) {
  if (n mod i == 0) {
    result = i;
    while (n mod i = 0)  n /= i;
  }
}
return max(n,result)

มีการทดสอบโมดูโลบางอย่างที่ยอดเยี่ยมเนื่องจาก n ไม่สามารถหารด้วย 6 ได้หากลบปัจจัยทั้งหมด 2 และ 3 ออกแล้ว คุณสามารถอนุญาตเฉพาะช่วงเวลาสำหรับ i ซึ่งแสดงในคำตอบอื่น ๆ อีกมากมายที่นี่

คุณสามารถรวมตะแกรง Eratosthenes ได้ที่นี่:

  • ขั้นแรกให้สร้างรายการจำนวนเต็มสูงสุดถึง sqrt (n)
  • ในการวนรอบทำเครื่องหมายทวีคูณทั้งหมดของ i จนถึง sqrt ใหม่ (n) ไม่ใช่ไพร์มและใช้ a while loop แทน
  • ตั้งค่า i เป็นหมายเลขเฉพาะถัดไปในรายการ

ดูคำถามนี้ด้วย


2

ฉันรู้ว่านี่ไม่ใช่วิธีแก้ปัญหาที่รวดเร็ว โพสต์หวังว่าจะเข้าใจวิธีแก้ปัญหาได้ช้ากว่า

 public static long largestPrimeFactor(long n) {

        // largest composite factor must be smaller than sqrt
        long sqrt = (long)Math.ceil(Math.sqrt((double)n));

        long largest = -1;

        for(long i = 2; i <= sqrt; i++) {
            if(n % i == 0) {
                long test = largestPrimeFactor(n/i);
                if(test > largest) {
                    largest = test;
                }
            }
        }

        if(largest != -1) {
            return largest;
        }

        // number is prime
        return n;
    } 

1

Python Iterative approach โดยกำจัดปัจจัยสำคัญทั้งหมดออกจากตัวเลข

def primef(n):
    if n <= 3:
        return n
    if n % 2 == 0:
        return primef(n/2)
    elif n % 3 ==0:
        return primef(n/3)
    else:
        for i in range(5, int((n)**0.5) + 1, 6):
            #print i
            if n % i == 0:
                return primef(n/i)
            if n % (i + 2) == 0:
                return primef(n/(i+2))
    return n

1

ฉันใช้อัลกอริธึมซึ่งจะทำการหารจำนวนต่อไปโดยใช้ Prime Prime ปัจจุบัน

โซลูชันของฉันใน python 3:

def PrimeFactor(n):
    m = n
    while n%2==0:
        n = n//2
    if n == 1:         # check if only 2 is largest Prime Factor 
        return 2
    i = 3
    sqrt = int(m**(0.5))  # loop till square root of number
    last = 0              # to store last prime Factor i.e. Largest Prime Factor
    while i <= sqrt :
        while n%i == 0:
            n = n//i       # reduce the number by dividing it by it's Prime Factor
            last = i
        i+=2
    if n> last:            # the remaining number(n) is also Factor of number 
        return n
    else:
        return last
print(PrimeFactor(int(input()))) 

อินพุต: 10 เอาต์พุต:5

อินพุต: 600851475143 เอาต์พุต:6857


0

นี่คือความพยายามของฉันใน c # การพิมพ์ครั้งสุดท้ายเป็นปัจจัยที่สำคัญที่สุดของจำนวน ฉันตรวจสอบแล้วและใช้งานได้

namespace Problem_Prime
{
  class Program
  {
    static void Main(string[] args)
    {
      /*
       The prime factors of 13195 are 5, 7, 13 and 29.

      What is the largest prime factor of the number 600851475143 ?
       */
      long x = 600851475143;
      long y = 2;
      while (y < x)
      {
        if (x % y == 0)
        {
          // y is a factor of x, but is it prime
          if (IsPrime(y))
          {
            Console.WriteLine(y);
          }
          x /= y;
        }

        y++;

      }
      Console.WriteLine(y);
      Console.ReadLine();
    }
    static bool IsPrime(long number)
    {
      //check for evenness
      if (number % 2 == 0)
      {
        if (number == 2)
        {
          return true;
        }
        return false;
      }
      //don't need to check past the square root
      long max = (long)Math.Sqrt(number);
      for (int i = 3; i <= max; i += 2)
      {
        if ((number % i) == 0)
        {
          return false;
        }
      }
      return true;
    }

  }
}

0
#python implementation
import math
n = 600851475143
i = 2
factors=set([])
while i<math.sqrt(n):
   while n%i==0:
       n=n/i
       factors.add(i)
   i+=1
factors.add(n)
largest=max(factors)
print factors
print largest

1
คือ 25 ปัจจัยสำคัญที่สุดของ 25
Will Ness

0

คำนวณจำนวนเฉพาะที่ใหญ่ที่สุดของตัวเลขโดยใช้การเรียกซ้ำใน C ++ การทำงานของรหัสได้อธิบายไว้ด้านล่าง:

int getLargestPrime(int number) {
    int factor = number; // assumes that the largest prime factor is the number itself
    for (int i = 2; (i*i) <= number; i++) { // iterates to the square root of the number till it finds the first(smallest) factor
        if (number % i == 0) { // checks if the current number(i) is a factor
            factor = max(i, number / i); // stores the larger number among the factors
            break; // breaks the loop on when a factor is found
        }
    }
    if (factor == number) // base case of recursion
        return number;
    return getLargestPrime(factor); // recursively calls itself
}

0

นี่คือวิธีของฉันในการคำนวณปัจจัยสำคัญที่สุดอย่างรวดเร็ว มันขึ้นอยู่กับข้อเท็จจริงที่ว่าการดัดแปลงxนั้นไม่มีปัจจัยที่ไม่สำคัญ เพื่อให้บรรลุเป้าหมายนั้นเราจะแบ่งxทันทีที่พบปัจจัย จากนั้นสิ่งเดียวที่เหลือคือการคืนปัจจัยที่ใหญ่ที่สุด มันจะเป็นนายกแล้ว

รหัส (Haskell):

f max' x i | i > x = max'
           | x `rem` i == 0 = f i (x `div` i) i  -- Divide x by its factor
           | otherwise = f max' x (i + 1)  -- Check for the next possible factor

g x = f 2 x 2

แต่นี่จะไม่พยายามหารด้วยเลขคู่ทั้งหมดด้วยหรือ
Janus Troelsen

0

อัลกอริทึม C ++ ต่อไปนี้ไม่ใช่วิธีที่ดีที่สุด แต่ใช้งานได้กับตัวเลขที่ต่ำกว่าหนึ่งพันล้านและมันค่อนข้างเร็ว

#include <iostream>
using namespace std;

// ------ is_prime ------
// Determines if the integer accepted is prime or not
bool is_prime(int n){
    int i,count=0;
    if(n==1 || n==2)
      return true;
    if(n%2==0)
      return false;
    for(i=1;i<=n;i++){
    if(n%i==0)
        count++;
    }
    if(count==2)
      return true;
    else
      return false;
 }
 // ------ nextPrime -------
 // Finds and returns the next prime number
 int nextPrime(int prime){
     bool a = false;
     while (a == false){
         prime++;
         if (is_prime(prime))
            a = true;
     }
  return prime;
 }
 // ----- M A I N ------
 int main(){

      int value = 13195;
      int prime = 2;
      bool done = false;

      while (done == false){
          if (value%prime == 0){
             value = value/prime;
             if (is_prime(value)){
                 done = true;
             }
          } else {
             prime = nextPrime(prime);
          }
      }
        cout << "Largest prime factor: " << value << endl;
 }

0

พบโซลูชันนี้บนเว็บโดย "James Wang"

public static int getLargestPrime( int number) {

    if (number <= 1) return -1;

    for (int i = number - 1; i > 1; i--) {
        if (number % i == 0) {
            number = i;
        }
    }
    return number;
}

0

ปัจจัยสำคัญที่ใช้ตะแกรง:

#include <bits/stdc++.h>
using namespace std;
#define N 10001  
typedef long long ll;
bool visit[N];
vector<int> prime;

void sieve()
{
            memset( visit , 0 , sizeof(visit));
            for( int i=2;i<N;i++ )
            {
                if( visit[i] == 0)
                {
                    prime.push_back(i);
                    for( int j=i*2; j<N; j=j+i )
                    {
                        visit[j] = 1;
                    }
                }
            }   
}
void sol(long long n, vector<int>&prime)
{
            ll ans = n;
            for(int i=0; i<prime.size() || prime[i]>n; i++)
            {
                while(n%prime[i]==0)
                {
                    n=n/prime[i];
                    ans = prime[i];
                }
            }
            ans = max(ans, n);
            cout<<ans<<endl;
}
int main() 
{
           ll tc, n;
           sieve();

           cin>>n;
           sol(n, prime);

           return 0;
}

-1

สำหรับฉันแล้วดูเหมือนว่าขั้นตอนที่ # 2 ของอัลกอริทึมที่กำหนดไม่ใช่วิธีการที่มีประสิทธิภาพทั้งหมด คุณไม่มีความคาดหวังที่สมเหตุสมผลว่าเป็นสิ่งสำคัญ

คำตอบก่อนหน้านี้ที่แนะนำ Sieve of Eratosthenes นั้นผิดอย่างสิ้นเชิง ฉันเพิ่งเขียนโปรแกรมสองโปรแกรมเพื่อแยกแยะ 123456789 หนึ่งรายการขึ้นอยู่กับตะแกรงหนึ่งรายการขึ้นอยู่กับสิ่งต่อไปนี้

1)  Test = 2 
2)  Current = Number to test 
3)  If Current Mod Test = 0 then  
3a)     Current = Current Div Test 
3b)     Largest = Test
3c)     Goto 3. 
4)  Inc(Test) 
5)  If Current < Test goto 4
6)  Return Largest

รุ่นนี้เร็วกว่าตะแกรง 90x

สิ่งที่เป็นอยู่ในตัวประมวลผลสมัยใหม่ประเภทของการดำเนินการมีความสำคัญน้อยกว่าจำนวนการดำเนินการไม่ต้องพูดถึงว่าอัลกอริทึมข้างต้นสามารถทำงานในแคชได้ตะแกรงไม่สามารถทำได้ ตะแกรงใช้การดำเนินการจำนวนมากที่โดดเด่นจากจำนวนรวมทั้งหมด

โปรดทราบว่าการแบ่งปัจจัยออกตามที่ระบุจะช่วยลดพื้นที่ที่ต้องทดสอบ


นั่นคือสิ่งที่ฉันพูด แต่ได้รับการโหวต :( ฉันเดาว่าปัญหาคือถ้าจำนวนนั้นมีปัจจัยสำคัญที่มีขนาดใหญ่มาก (เช่นตัวเอง) ดังนั้นวิธีการนี้จะต้องวนซ้ำไปเรื่อย ๆ จนถึงจำนวนนั้นในหลายกรณี แต่วิธีการนี้ค่อนข้างมีประสิทธิภาพ.
nickf

การอ่านย้อนกลับของคุณมันเหมือนกัน แต่ส่วนแรกของคุณสับสน
Loren Pechtel

ลองว่าในจำนวนนี้ 143816789988504044536402352738195137863656439 แจ้งให้เราทราบว่ามีประสิทธิภาพนี้คือ ...
MichaelICE

-1

คำนวณรายการที่เก็บหมายเลขเฉพาะก่อนเช่น 2 3 5 7 11 13 ...

ทุกครั้งที่คุณแยกตัวประกอบจำนวนใช้การใช้งานโดย Triptych แต่วนซ้ำรายการหมายเลขเฉพาะแทนจำนวนเต็มธรรมชาติ


-1

ด้วย Java:

สำหรับintค่า:

public static int[] primeFactors(int value) {
    int[] a = new int[31];
    int i = 0, j;
    int num = value;
    while (num % 2 == 0) {
        a[i++] = 2;
        num /= 2;
    }
    j = 3;
    while (j <= Math.sqrt(num) + 1) {
        if (num % j == 0) {
            a[i++] = j;
            num /= j;
        } else {
            j += 2;
        }
    }
    if (num > 1) {
        a[i++] = num;
    }
    int[] b = Arrays.copyOf(a, i);
    return b;
}

สำหรับlongค่า:

static long[] getFactors(long value) {
    long[] a = new long[63];
    int i = 0;
    long num = value;
    while (num % 2 == 0) {
        a[i++] = 2;
        num /= 2;
    }
    long j = 3;
    while (j <= Math.sqrt(num) + 1) {
        if (num % j == 0) {
            a[i++] = j;
            num /= j;
        } else {
            j += 2;
        }
    }
    if (num > 1) {
        a[i++] = num;
    }
    long[] b = Arrays.copyOf(a, i);
    return b;
}

-2

นี่อาจจะไม่เร็วกว่านี้เสมอไป แต่จะมองโลกในแง่ดีเกี่ยวกับตัวหารสำคัญ:

  1. N คือหมายเลขของคุณ
  2. ถ้ามันเป็นนายกแล้ว return(N)
  3. คำนวณจำนวนเฉพาะจนถึง Sqrt(N)
  4. ผ่านช่วงเวลาตามลำดับจากมากไปน้อย (ใหญ่ที่สุดก่อน)
    • ถ้าเป็นเช่นN is divisible by Primeนั้นReturn(Prime)

แก้ไข: ในขั้นตอนที่ 3 คุณสามารถใช้ Sieve of Eratosthenes หรือ Sieve of Atkins หรืออะไรก็ได้ที่คุณชอบ แต่ด้วยตัวเองตะแกรงจะไม่พบว่าคุณเป็นปัจจัยสำคัญที่สุด (นั่นเป็นเหตุผลที่ฉันไม่เลือกโพสต์ของ SQLMenace เป็นคำตอบอย่างเป็นทางการ ... )


1
คุณไม่จำเป็นต้องทำการทดลองเพื่อพิจารณาว่าเป็นหมายเลขเฉพาะหรือไม่ (ขั้นตอนที่ 2) นอกจากนี้ให้ลองค้นหาปัจจัยสำคัญที่ใหญ่ที่สุดของ 15 ค่าเฉพาะช่วงถึง sqrt (15) คือ 2 และ 3 แต่ตัวประกอบสำคัญที่สุดคือ 5 ใช่ไหม? ในทำนองเดียวกันกับ 20.
Jonathan Leffler

-3

ฉันคิดว่ามันจะเป็นการดีถ้าเก็บบางช่วงเวลาที่เป็นไปได้ที่เล็กลงแล้ว n และวนซ้ำเพื่อหาตัวหารที่ใหญ่ที่สุด คุณจะได้รับเฉพาะจากprime-numbers.org

แน่นอนฉันคิดว่าหมายเลขของคุณไม่ใหญ่เกินไป :)


-3

ไม่เร็วที่สุด แต่ใช้งานได้!

    static bool IsPrime(long num)
    {
        long checkUpTo = (long)Math.Ceiling(Math.Sqrt(num));
        for (long i = 2; i <= checkUpTo; i++)
        {
            if (num % i == 0)
                return false;
        }
        return true;
    }

นี่ไม่ใช่คำตอบสำหรับคำถาม ;-) คำถามคือเกี่ยวกับการค้นหาปัจจัยสำคัญที่ใหญ่ที่สุดไม่ใช่การตรวจสอบสิ่งดั้งเดิม
Hans-Peter Störr

มันมีประสิทธิภาพมากขึ้นเพื่อ initialise ห่วงของคุณเป็น (ยาว i = 3; ฉัน <checkUpTo; i + = 2)
CJK

-3

นี่คือฟังก์ชั่นเดียวกับ @ Triptych ที่ให้ไว้เป็นเครื่องกำเนิดซึ่งได้รับการปรับให้เรียบง่ายเล็กน้อย

def primes(n):
    d = 2
    while (n > 1):
        while (n%d==0):
            yield d
            n /= d
        d += 1

สามารถพบสูงสุดเฉพาะได้โดยใช้:

n= 373764623
max(primes(n))

และรายการปัจจัยที่พบโดยใช้:

list(primes(n))

-6
#include<stdio.h>
#include<conio.h>
#include<math.h>
#include <time.h>

factor(long int n)
{
long int i,j;
while(n>=4)
 {
if(n%2==0) {  n=n/2;   i=2;   }

 else
 { i=3;
j=0;
  while(j==0)
  {
   if(n%i==0)
   {j=1;
   n=n/i;
   }
   i=i+2;
  }
 i-=2;
 }
 }
return i;
 }

 void main()
 { 
  clock_t start = clock();
  long int n,sp;
  clrscr();
  printf("enter value of n");
  scanf("%ld",&n);
  sp=factor(n);
  printf("largest prime factor is %ld",sp);

  printf("Time elapsed: %f\n", ((double)clock() - start) / CLOCKS_PER_SEC);
  getch();
 }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.