รับอาร์เรย์ของตัวเลขส่งคืนอาร์เรย์ของผลิตภัณฑ์ของตัวเลขอื่น ๆ ทั้งหมด (ไม่มีการหาร)


186

ฉันถูกถามคำถามนี้ในการสัมภาษณ์งานและฉันต้องการทราบว่าคนอื่นจะแก้ไขได้อย่างไร ฉันรู้สึกสบายใจกับ Java ที่สุด แต่ยินดีต้อนรับโซลูชันในภาษาอื่น

รับอาร์เรย์ของตัวเลขnumsกลับอาร์เรย์ของตัวเลขproductsที่เป็นผลิตภัณฑ์ของทั้งหมดproducts[i]nums[j], j != i

Input : [1, 2, 3, 4, 5]
Output: [(2*3*4*5), (1*3*4*5), (1*2*4*5), (1*2*3*5), (1*2*3*4)]
      = [120, 60, 40, 30, 24]

คุณต้องทำสิ่งนี้O(N)โดยไม่ใช้การหาร


49
คำถามนี้เกิดขึ้นสองสามครั้งในสัปดาห์ที่แล้วหรือประมาณนั้น คุณทุกคนสัมภาษณ์กับ บริษัท เดียวกันหรือไม่? :)
Michael Mrozek

ฉันกำลัง[interview-questions]ค้นหาแท็กที่กำลังมองหาอยู่ คุณมีลิงค์ไหมถ้าคุณเจอมัน?
polygenelubricants

2
@Michael: คำถามที่ช่วยให้การแบ่ง ฉันห้ามอย่างชัดเจน ฉันว่าพวกเขาสองคำถามที่แตกต่างกัน
polygenelubricants

8
การแทนที่ส่วนที่มีบันทึก (a / b) = log (a) -log (b) และ voila!
ldog

1
ลองจินตนาการว่าถ้ามี 1 หรือมากกว่า 1 ศูนย์ในอาเรย์คุณจะรับมือกับเรื่องนี้อย่างไร?
gst

คำตอบ:


257

คำอธิบายของวิธีการpolygenelubricantsคือ: เคล็ดลับคือการสร้างอาร์เรย์ (ในกรณีขององค์ประกอบ 4)

{              1,         a[0],    a[0]*a[1],    a[0]*a[1]*a[2],  }
{ a[1]*a[2]*a[3],    a[2]*a[3],         a[3],                 1,  }

ซึ่งทั้งสองสามารถทำได้ใน O (n) โดยเริ่มต้นที่ขอบซ้ายและขวาตามลำดับ

จากนั้นการคูณสององค์ประกอบอาร์เรย์โดยองค์ประกอบให้ผลลัพธ์ที่ต้องการ

รหัสของฉันจะเป็นดังนี้:

int a[N] // This is the input
int products_below[N];
p=1;
for(int i=0;i<N;++i) {
  products_below[i]=p;
  p*=a[i];
}

int products_above[N];
p=1;
for(int i=N-1;i>=0;--i) {
  products_above[i]=p;
  p*=a[i];
}

int products[N]; // This is the result
for(int i=0;i<N;++i) {
  products[i]=products_below[i]*products_above[i];
}

หากคุณต้องอยู่ในพื้นที่ O (1) ด้วยคุณสามารถทำได้ (ซึ่ง IMHO ชัดเจนน้อยกว่า)

int a[N] // This is the input
int products[N];

// Get the products below the current index
p=1;
for(int i=0;i<N;++i) {
  products[i]=p;
  p*=a[i];
}

// Get the products above the curent index
p=1;
for(int i=N-1;i>=0;--i) {
  products[i]*=p;
  p*=a[i];
}

4
นี่คือ O (n) runtime แต่ก็ยัง O (n) ในความซับซ้อนของพื้นที่ คุณสามารถทำได้ในพื้นที่ O (1) ฉันหมายความว่านอกจากขนาดของอินพุตและเอาต์พุตคอนเทนเนอร์แน่นอน
wilhelmtell

8
ฉลาดมาก! มีชื่อสำหรับอัลกอริทึมนี้หรือไม่?
fastcodejava

2
@MichaelAnderson คนทำงานที่ยอดเยี่ยม แต่โปรดบอกเหตุผลหลักที่อยู่เบื้องหลังเรื่องนี้และคุณจะเริ่มต้นอย่างไรเมื่อคุณได้รับข้อกำหนด
ACBalaji

3
อัลกอริทึมจะล้มเหลวหากองค์ประกอบใด ๆ เป็น 0 ดังนั้นอย่าลืมตรวจสอบ 0 เพื่อข้าม
มณี

2
@Mani อัลกอริทึมใช้ได้ถ้ามีการตั้งค่าองค์ประกอบเป็น 0 อย่างไรก็ตามอาจเป็นไปได้ที่จะสแกนอินพุตสำหรับองค์ประกอบดังกล่าวและมีประสิทธิภาพมากขึ้นหากพบว่า หากมีสององค์ประกอบศูนย์ผลลัพธ์ทั้งหมดจะเป็นศูนย์และหากมีเพียงองค์ประกอบเดียวให้กล่าวว่าv_i=0รายการที่ไม่ใช่ศูนย์เดียวในผลลัพธ์คือองค์ประกอบ ith แต่ผมสงสัยว่าการเพิ่มผ่านการตรวจสอบและนับองค์ประกอบศูนย์จะเบี่ยงเบนจากความชัดเจนของการแก้ปัญหาและอาจจะไม่ได้ทำให้ได้รับประสิทธิภาพที่แท้จริงใด ๆ ในกรณีส่วนใหญ่ ..
ไมเคิลเดอร์สัน

52

นี่คือฟังก์ชั่นวนซ้ำขนาดเล็ก (ใน C ++) เพื่อทำการปรับเปลี่ยน ต้องใช้พื้นที่พิเศษ O (n) (บนสแต็ก) สมมติว่าอาร์เรย์อยู่ใน a และ N ถือความยาวอาร์เรย์เรามี

int multiply(int *a, int fwdProduct, int indx) {
    int revProduct = 1;
    if (indx < N) {
       revProduct = multiply(a, fwdProduct*a[indx], indx+1);
       int cur = a[indx];
       a[indx] = fwdProduct * revProduct;
       revProduct *= cur;
    }
    return revProduct;
}

ใครสามารถอธิบายการสอบถามซ้ำนี้ได้บ้าง
nikhil

1
@ Nikhil มันจะเรียกซ้ำก่อนจำผลิตภัณฑ์ขั้นกลางในที่สุดสร้างผลิตภัณฑ์จำนวนสำหรับnum[N-1]; จากนั้นในทางกลับจะคำนวณส่วนที่สองของการคูณซึ่งจะใช้ในการปรับเปลี่ยนอาร์เรย์ตัวเลขในสถานที่
Ja͢ck

ลองจินตนาการว่าถ้ามี 1 หรือมากกว่า 1 ศูนย์ในอาเรย์คุณจะรับมือกับเรื่องนี้อย่างไร?
gst

18

นี่คือความพยายามของฉันที่จะแก้ปัญหาใน Java ขออภัยในการจัดรูปแบบที่ไม่ได้มาตรฐาน แต่รหัสมีการทำซ้ำจำนวนมากและนี่คือสิ่งที่ดีที่สุดที่ฉันสามารถทำได้เพื่อให้สามารถอ่านได้

import java.util.Arrays;

public class Products {
    static int[] products(int... nums) {
        final int N = nums.length;
        int[] prods = new int[N];
        Arrays.fill(prods, 1);
        for (int
           i = 0, pi = 1    ,  j = N-1, pj = 1  ;
           (i < N)         && (j >= 0)          ;
           pi *= nums[i++]  ,  pj *= nums[j--]  )
        {
           prods[i] *= pi   ;  prods[j] *= pj   ;
        }
        return prods;
    }
    public static void main(String[] args) {
        System.out.println(
            Arrays.toString(products(1, 2, 3, 4, 5))
        ); // prints "[120, 60, 40, 30, 24]"
    }
}

คงห่วงอยู่และpi = nums[0] * nums[1] *.. nums[i-1] ส่วนด้านซ้ายคือ "คำนำหน้า" ตรรกะและส่วนด้านขวาคือ "ต่อท้าย" ตรรกะpj = nums[N-1] * nums[N-2] *.. nums[j+1]ij


ซับซ้ำแบบหนึ่งซ้ำ

Jasmeetให้โซลูชันแบบเรียกซ้ำ (สวยงาม!) ฉันเปลี่ยนมันให้เป็น (น่าเกลียด!) Java one-liner มันทำการแก้ไขในสถานที่ที่มีO(N)พื้นที่ชั่วคราวในกอง

static int multiply(int[] nums, int p, int n) {
    return (n == nums.length) ? 1
      : nums[n] * (p = multiply(nums, nums[n] * (nums[n] = p), n + 1))
          + 0*(nums[n] *= p);
}

int[] arr = {1,2,3,4,5};
multiply(arr, 1, 0);
System.out.println(Arrays.toString(arr));
// prints "[120, 60, 40, 30, 24]"

3
ฉันคิดว่าลูป 2 ตัวแปรทำให้ยากต่อการเข้าใจเกินความจำเป็น (อย่างน้อยสำหรับสมองที่แย่ของฉัน!) ลูปสองวงที่แยกกันจะทำงานเช่นกัน
Guillaume

นั่นเป็นเหตุผลที่ฉันแยกรหัสออกเป็นซ้าย / ขวาเพื่อแสดงว่าทั้งสองเป็นอิสระจากกัน ฉันไม่แน่ใจว่ามันใช้งานได้จริงหรือไม่แม้ว่า =)
polygenelubricants

15

แปลโซลูชันของ Michael Anderson เป็น Haskell:

otherProducts xs = zipWith (*) below above

     where below = scanl (*) 1 $ init xs

           above = tail $ scanr (*) 1 xs

13

แอบหลีกเลี่ยงกฎ "ไม่มีฝ่าย":

sum = 0.0
for i in range(a):
  sum += log(a[i])

for i in range(a):
  output[i] = exp(sum - log(a[i]))

2
nitpick: เท่าที่ผมทราบคอมพิวเตอร์ใช้ลอการิทึมใช้การขยายตัวทวินามของพวกเขา - ซึ่งไม่จำเป็นต้องมีส่วน ...

10

ที่นี่คุณจะไปโซลูชั่นที่เรียบง่ายและสะอาดด้วยความซับซ้อน O (N):

int[] a = {1,2,3,4,5};
    int[] r = new int[a.length];
    int x = 1;
    r[0] = 1;
    for (int i=1;i<a.length;i++){
        r[i]=r[i-1]*a[i-1];
    }
    for (int i=a.length-1;i>0;i--){
        x=x*a[i];
        r[i-1]=x*r[i-1];
    }
    for (int i=0;i<r.length;i++){
        System.out.println(r[i]);
    }

6

C ++, O (n):

long long prod = accumulate(in.begin(), in.end(), 1LL, multiplies<int>());
transform(in.begin(), in.end(), back_inserter(res),
          bind1st(divides<long long>(), prod));

9
ไม่อนุญาตให้แบ่ง
Michael Anderson

แม้ว่าจะยังคงเป็นโค้ดที่ดูดีมาก ด้วยข้อจำกัดความรับผิดชอบที่ใช้การแบ่งฉันยังคง upvote หากคำอธิบายที่ได้รับ
polygenelubricants

ประณามฉันไม่ได้อ่านคำถามเลย : s @polygenelubricants คำอธิบาย: ความคิดคือการทำมันในสองขั้นตอน ก่อนอื่นนำแฟคทอเรียลของลำดับแรกของตัวเลข นั่นคือสิ่งที่อัลกอริทึมแบบสะสม (โดยค่าเริ่มต้นจะเพิ่มตัวเลข แต่สามารถทำการดำเนินการแบบไบนารีอื่น ๆ เพื่อแทนที่การเพิ่มในกรณีนี้คือการคูณ) ถัดไปฉันวนซ้ำตามลำดับการป้อนข้อมูลเป็นครั้งที่สองเปลี่ยนให้องค์ประกอบที่สอดคล้องกันในลำดับผลลัพธ์เป็นแฟคทอเรียลที่ฉันคำนวณในขั้นตอนก่อนหน้าหารด้วยองค์ประกอบที่เกี่ยวข้องในลำดับอินพุต
wilhelmtell

1
"แฟคทอเรียลของลำดับแรก"? WTF? ฉันหมายถึงผลผลิตขององค์ประกอบลำดับ
wilhelmtell

5
  1. เดินทางไปทางซ้าย -> ขวาและเก็บผลิตภัณฑ์ไว้ เรียกมันว่าอดีต -> O (n)
  2. Travel Right -> left เก็บผลิตภัณฑ์ เรียกมันว่าอนาคต -> O (n)
  3. ผลลัพธ์ [i] = อดีต [i-1] * อนาคต [i + 1] -> O (n)
  4. ที่ผ่านมา [-1] = 1; และอนาคต [n + 1] = 1;

บน)


3

นี่คือทางออกของฉันใน C ++ ที่ทันสมัย มันใช้ประโยชน์จากstd::transformและจดจำได้ง่าย

รหัสออนไลน์ (wandbox)

#include<algorithm>
#include<iostream>
#include<vector>

using namespace std;

vector<int>& multiply_up(vector<int>& v){
    v.insert(v.begin(),1);
    transform(v.begin()+1, v.end()
             ,v.begin()
             ,v.begin()+1
             ,[](auto const& a, auto const& b) { return b*a; }
             );
    v.pop_back();
    return v;
}

int main() {
    vector<int> v = {1,2,3,4,5};
    auto vr = v;

    reverse(vr.begin(),vr.end());
    multiply_up(v);
    multiply_up(vr);
    reverse(vr.begin(),vr.end());

    transform(v.begin(),v.end()
             ,vr.begin()
             ,v.begin()
             ,[](auto const& a, auto const& b) { return b*a; }
             );

    for(auto& i: v) cout << i << " "; 
}

2

นี่คือ O (n ^ 2) แต่ f # สวยมาก:

List.fold (fun seed i -> List.mapi (fun j x -> if i=j+1 then x else x*i) seed) 
          [1;1;1;1;1]
          [1..5]

ฉันไม่แน่ใจว่าวิธีแก้ปัญหา O (n ^ 2) ขนาดมหึมาอย่างใดอย่างหนึ่งสำหรับปัญหา O (n) นั้น "สวยงาม"
นักฟิสิกส์บ้า

2

ทำการประมาณผลคูณของตัวเลขทางซ้ายและทางขวาของแต่ละองค์ประกอบ สำหรับทุกองค์ประกอบค่าที่ต้องการคือผลิตภัณฑ์ของผลิตภัณฑ์ของ neigbours

#include <stdio.h>

unsigned array[5] = { 1,2,3,4,5};

int main(void)
{
unsigned idx;

unsigned left[5]
        , right[5];
left[0] = 1;
right[4] = 1;

        /* calculate products of numbers to the left of [idx] */
for (idx=1; idx < 5; idx++) {
        left[idx] = left[idx-1] * array[idx-1];
        }

        /* calculate products of numbers to the right of [idx] */
for (idx=4; idx-- > 0; ) {
        right[idx] = right[idx+1] * array[idx+1];
        }

for (idx=0; idx <5 ; idx++) {
        printf("[%u] Product(%u*%u) = %u\n"
                , idx, left[idx] , right[idx]  , left[idx] * right[idx]  );
        }

return 0;
}

ผลลัพธ์:

$ ./a.out
[0] Product(1*120) = 120
[1] Product(1*60) = 60
[2] Product(2*20) = 40
[3] Product(6*5) = 30
[4] Product(24*1) = 24

(UPDATE: ตอนนี้ฉันมองใกล้ ๆ นี่ใช้วิธีเดียวกับ Michael Anderson, Daniel Migowski และ polygenelubricants ด้านบน)


อัลกอริทึมนี้ชื่ออะไร
onepiece

1

หากิน:

ใช้สิ่งต่อไปนี้:

public int[] calc(int[] params) {

int[] left = new int[n-1]
in[] right = new int[n-1]

int fac1 = 1;
int fac2 = 1;
for( int i=0; i<n; i++ ) {
    fac1 = fac1 * params[i];
    fac2 = fac2 * params[n-i];
    left[i] = fac1;
    right[i] = fac2; 
}
fac = 1;

int[] results = new int[n];
for( int i=0; i<n; i++ ) {
    results[i] = left[i] * right[i];
}

ใช่ฉันแน่ใจว่าฉันพลาด i-1 บางตัวแทนที่จะเป็น i แต่นั่นเป็นวิธีแก้ปัญหา


1

นอกจากนี้ยังมีทางออกที่ไม่เหมาะสม O (N ^ (3/2)) มันค่อนข้างน่าสนใจทีเดียว

การประมวลผลล่วงหน้าครั้งแรกในแต่ละการคูณบางส่วนของขนาด N ^ 0.5 (ซึ่งจะทำในความซับซ้อนของเวลา O (N)) จากนั้นการคำนวณสำหรับค่าอื่น ๆ ของแต่ละจำนวนสามารถทำได้ในเวลา 2 * O (N ^ 0.5) (เพราะอะไรเพราะคุณจำเป็นต้องใช้หลายองค์ประกอบสุดท้ายของตัวเลขอื่น ๆ ((N ^ 0.5) - 1) และคูณผลลัพธ์ด้วย ((N ^ 0.5) - 1) ตัวเลขที่เป็นของกลุ่มหมายเลขปัจจุบัน) การทำเช่นนี้สำหรับแต่ละหมายเลขหนึ่งสามารถรับเวลา O (N ^ (3/2))

ตัวอย่าง:

4 6 7 2 3 1 9 5 8

ผลลัพธ์บางส่วน: 4 * 6 * 7 = 168 2 * 3 * 1 = 6 9 * 5 * 8 = 360

ในการคำนวณค่า 3 เราต้องคูณค่าของกลุ่มอื่นกับ 168 * 360 แล้วคูณด้วย 2 * 1


1
public static void main(String[] args) {
    int[] arr = { 1, 2, 3, 4, 5 };
    int[] result = { 1, 1, 1, 1, 1 };
    for (int i = 0; i < arr.length; i++) {
        for (int j = 0; j < i; j++) {
            result[i] *= arr[j];

        }
        for (int k = arr.length - 1; k > i; k--) {
            result[i] *= arr[k];
        }
    }
    for (int i : result) {
        System.out.println(i);
    }
}

วิธีการแก้ปัญหานี้ฉันมาด้วยและฉันพบมันชัดเจนว่าคุณคิดอย่างไร


1
โซลูชันของคุณมีความซับซ้อนของเวลา O (n ^ 2)
นักฟิสิกส์บ้า

1
def productify(arr, prod, i):
    if i < len(arr):
            prod.append(arr[i - 1] * prod[i - 1]) if i > 0 else prod.append(1)
            retval = productify(arr, prod, i + 1)
            prod[i] *= retval
            return retval * arr[i]
    return 1

arr = [1, 2, 3, 4, 5] prod = [] สร้างผลิตภัณฑ์ (arr, prod, 0) print prod


1

การทำให้สมบูรณ์ที่นี่คือรหัสใน Scala:

val list1 = List(1, 2, 3, 4, 5)
for (elem <- list1) println(list1.filter(_ != elem) reduceLeft(_*_))

สิ่งนี้จะพิมพ์ออกมาดังต่อไปนี้:

120
60
40
30
24

โปรแกรมจะกรอง elem ปัจจุบัน (_! = elem); และเพิ่มรายการใหม่ด้วยวิธีการลดระดับ ฉันคิดว่านี่จะเป็น O (n) ถ้าคุณใช้มุมมองสกาล่าหรือ Iterator สำหรับขี้เกียจ eval


แม้จะมีความสง่างามมาก แต่ก็ใช้งานไม่ได้หากมีองค์ประกอบอื่น ๆ ที่มีค่าเท่ากัน: val list1 = รายการ (1, 7, 3, 3, 4, 4)
Giordano Scalzo

ฉันทดสอบโค้ดอีกครั้งด้วยค่าการทำซ้ำ มันผลิตดังต่อไปนี้ 1008 144 112 112 63 63 ฉันคิดว่ามันถูกต้องสำหรับองค์ประกอบที่กำหนด
Billz

1

ตามคำตอบ Billz - ขอโทษที่ฉันไม่สามารถแสดงความคิดเห็น แต่นี่เป็นรุ่นสกาล่าที่จัดการรายการที่ซ้ำกันในรายการได้อย่างถูกต้องและอาจเป็น O (n):

val list1 = List(1, 7, 3, 3, 4, 4)
val view = list1.view.zipWithIndex map { x => list1.view.patch(x._2, Nil, 1).reduceLeft(_*_)}
view.force

ผลตอบแทน:

List(1008, 144, 336, 336, 252, 252)

1

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

//No division operation allowed
// keep substracting divisor from dividend, until dividend is zero or less than divisor
function calculateProducsExceptCurrent_NoDivision(input){
  var res = [];
  var totalProduct = 1;
  //calculate the total product
  for(var i = 0; i < input.length; i++){
    totalProduct = totalProduct * input[i];
  }
  //populate the result array by "dividing" each value
  for(var i = 0; i < input.length; i++){
    var timesSubstracted = 0;
    var divisor = input[i];
    var dividend = totalProduct;
    while(divisor <= dividend){
      dividend = dividend - divisor;
      timesSubstracted++;
    }
    res.push(timesSubstracted);
  }
  return res;
}

1

ฉันใช้กับ C #:

    public int[] ProductExceptSelf(int[] nums)
    {
        int[] returnArray = new int[nums.Length];
        List<int> auxList = new List<int>();
        int multTotal = 0;

        // If no zeros are contained in the array you only have to calculate it once
        if(!nums.Contains(0))
        {
            multTotal = nums.ToList().Aggregate((a, b) => a * b);

            for (int i = 0; i < nums.Length; i++)
            {
                returnArray[i] = multTotal / nums[i];
            }
        }
        else
        {
            for (int i = 0; i < nums.Length; i++)
            {
                auxList = nums.ToList();
                auxList.RemoveAt(i);
                if (!auxList.Contains(0))
                {
                    returnArray[i] = auxList.Aggregate((a, b) => a * b);
                }
                else
                {
                    returnArray[i] = 0;
                }
            }
        }            

        return returnArray;
    }

1

เราสามารถแยกรายการnums[j](ที่j != i) ออกก่อนจากนั้นรับผลิตภัณฑ์ที่เหลือ ต่อไปนี้เป็นวิธีpython wayแก้ปริศนานี้:

from functools import reduce
def products(nums):
    return [ reduce(lambda x,y: x * y, nums[:i] + nums[i+1:]) for i in range(len(nums)) ]
print(products([1, 2, 3, 4, 5]))

[out]
[120, 60, 40, 30, 24]

0

วิธีแก้ปัญหานี้ถือได้ว่าเป็น C / C ++ ให้บอกว่าเรามีอาร์เรย์ "a" ที่มีองค์ประกอบ n อย่างเช่น [n] จากนั้นโค้ดหลอกจะเป็นดังนี้

for(j=0;j<n;j++)
  { 
    prod[j]=1;

    for (i=0;i<n;i++)
    {   
        if(i==j)
        continue;  
        else
        prod[j]=prod[j]*a[i];
  }

0

อีกวิธีแก้ปัญหาโดยใช้การหาร ด้วยการแวะผ่านสองครั้ง คูณองค์ประกอบทั้งหมดแล้วเริ่มหารด้วยองค์ประกอบแต่ละรายการ


0
{-
โซลูชันแบบเรียกซ้ำโดยใช้ชุดย่อย sqrt (n) ทำงานใน O (n)

คำนวณคำตอบแบบซ้ำ ๆ บน sqrt (n) ชุดย่อยขนาด sqrt (n) 
จากนั้นเกิดขึ้นอีกครั้งกับผลรวมผลิตภัณฑ์ของแต่ละชุดย่อย
จากนั้นสำหรับแต่ละองค์ประกอบในแต่ละชุดย่อยจะคำนวณผลิตภัณฑ์ด้วย
ผลรวมของผลิตภัณฑ์อื่น ๆ ทั้งหมด
จากนั้นแฟรตย่อยทั้งหมด

การเกิดซ้ำในเวลาทำงานคือ T (n) = sqrt (n) * T (sqrt (n)) + T (sqrt (n)) + n

สมมติว่า T (n) ≤ cn ใน O (n)

T (n) = sqrt (n) * T (sqrt (n)) + T (sqrt (n)) + n
    ≤ sqrt (n) * c * sqrt (n) + c * sqrt (n) + n
    ≤ c * n + c * sqrt (n) + n
    ≤ (2c + 1) * n
    ∈ O (n)

โปรดทราบว่าสามารถคำนวณ Ceiling (sqrt (n)) โดยใช้การค้นหาแบบไบนารี 
และการวนซ้ำ O (logn) หากไม่อนุญาตให้ใช้คำสั่ง sqrt
-}

otherProducts [] = []
otherProducts [x] = [1]
otherProducts [x, y] = [y, x]
otherProducts a = foldl '(++) [] $ zipWith (\ sp -> แผนที่ (* p) s) แก้ไขชุดย่อยเซ็ตย่อย
    ที่ไหน 
      n = ความยาว

      - ขนาดชุดย่อย ต้องการว่า 1 <s <n
      s = เพดาน $ sqrt $ จากค่าเริ่มต้น n

      modifiedSubsets = map เซ็ทย่อยผลิตภัณฑ์อื่น ๆ
      subsetOtherProducts = otherProducts $ map เซ็ตย่อยผลิตภัณฑ์

      subsets = ย้อนกลับ $ loop a []
          โดยที่ loop [] acc = acc
                วนรอบ a acc = วนรอบ (ปล่อย sa) ((ใช้ sa): acc)

0

นี่คือรหัสของฉัน:

int multiply(int a[],int n,int nextproduct,int i)
{
    int prevproduct=1;
    if(i>=n)
        return prevproduct;
    prevproduct=multiply(a,n,nextproduct*a[i],i+1);
    printf(" i=%d > %d\n",i,prevproduct*nextproduct);
    return prevproduct*a[i];
}

int main()
{
    int a[]={2,4,1,3,5};
    multiply(a,5,1,0);
    return 0;
}

0

นี่คือตัวอย่างการทำงานเล็กน้อยโดยใช้ C #:

            Func<long>[] backwards = new Func<long>[input.Length];
            Func<long>[] forwards = new Func<long>[input.Length];

            for (int i = 0; i < input.Length; ++i)
            {
                var localIndex = i;
                backwards[i] = () => (localIndex > 0 ? backwards[localIndex - 1]() : 1) * input[localIndex];
                forwards[i] = () => (localIndex < input.Length - 1 ? forwards[localIndex + 1]() : 1) * input[localIndex];
            }

            var output = new long[input.Length];
            for (int i = 0; i < input.Length; ++i)
            {
                if (0 == i)
                {
                    output[i] = forwards[i + 1]();
                }
                else if (input.Length - 1 == i)
                {
                    output[i] = backwards[i - 1]();
                }
                else
                {
                    output[i] = forwards[i + 1]() * backwards[i - 1]();
                }
            }

ฉันไม่ได้ทั้งหมดบางอย่างที่ว่านี้คือ O (n) เนื่องจากกึ่ง recursion ของ funcs สร้าง แต่ผลการทดสอบของฉันชี้ให้เห็นว่ามันเป็น O (n) ในเวลาที่


0

// นี่คือโซลูชันแบบเรียกซ้ำใน Java // เรียกว่าดังต่อไปนี้จากผลิตภัณฑ์หลัก (a, 1,0);

public static double product(double[] a, double fwdprod, int index){
    double revprod = 1;
    if (index < a.length){
        revprod = product2(a, fwdprod*a[index], index+1);
        double cur = a[index];
        a[index] = fwdprod * revprod;
        revprod *= cur;
    }
    return revprod;
}

0

ทางออกที่เรียบร้อยพร้อมรันไทม์ O (n):

  1. สำหรับแต่ละองค์ประกอบคำนวณผลิตภัณฑ์ขององค์ประกอบทั้งหมดที่เกิดขึ้นก่อนหน้านั้นและเก็บไว้ในอาร์เรย์ "pre"
  2. สำหรับแต่ละองค์ประกอบคำนวณผลิตภัณฑ์ขององค์ประกอบทั้งหมดที่เกิดขึ้นหลังจากองค์ประกอบนั้นและเก็บไว้ในอาร์เรย์ "โพสต์"
  3. สร้าง "ผลลัพธ์" ของอาร์เรย์สุดท้ายสำหรับองค์ประกอบ i

    result[i] = pre[i-1]*post[i+1];
    

1
นี่เป็นโซลูชันเดียวกับที่ยอมรับใช่ไหม
โทมัส Ahle

0
function solution($array)
{
    $result = [];
    foreach($array as $key => $value){
        $copyOfOriginalArray = $array;
        unset($copyOfOriginalArray[$key]);
        $result[$key] = multiplyAllElemets($copyOfOriginalArray);
    }
    return $result;
}

/**
 * multiplies all elements of array
 * @param $array
 * @return int
 */
function multiplyAllElemets($array){
    $result = 1;
    foreach($array as $element){
        $result *= $element;
    }
    return $result;
}

$array = [1, 9, 2, 7];

print_r(solution($array));

0

O(N)นี่คือแนวคิดที่เรียบง่ายอีกซึ่งจะช่วยแก้ปัญหาที่เกิดขึ้นใน

        int[] arr = new int[] {1, 2, 3, 4, 5};
        int[] outArray = new int[arr.length]; 
        for(int i=0;i<arr.length;i++){
            int res=Arrays.stream(arr).reduce(1, (a, b) -> a * b);
            outArray[i] = res/arr[i];
        }
        System.out.println(Arrays.toString(outArray));

0

ฉันมีวิธีแก้ปัญหาเกี่ยวกับO(n)พื้นที่และO(n^2)เวลาที่ซับซ้อนด้านล่าง

public static int[] findEachElementAsProduct1(final int[] arr) {

        int len = arr.length;

//        int[] product = new int[len];
//        Arrays.fill(product, 1);

        int[] product = IntStream.generate(() -> 1).limit(len).toArray();


        for (int i = 0; i < len; i++) {

            for (int j = 0; j < len; j++) {

                if (i == j) {
                    continue;
                }

                product[i] *= arr[j];
            }
        }

        return product;
    }
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.