Related
I have an assignment to solve using dynamic programming the following problem:
There is a rectangular sheet and a set of rectangular elements of given dimensions and value. The task is to divide the sheet into elements of given dimensions, so that the sum of values of the elements is maximum. Find this sum and a tree of consequent cuts.
There are following conditions:
It is NOT possible to rotate the given elements.
It is possible to cut out unlimited number of certain types of
elements.
It is possible that some parts of the sheet will remain unused.
The only possible way to cut the sheet is by a straight
line, so that you again obtain two smaller rectangles.
The problem is solved. Solution can be found below.
==========================================================================
I understand the problem for one dimension, which comes to the rod cutting problem. You divide the rod into the smallest possible pieces, take the first one and check if you can build it with the given segments. Remember the weight you'll get with building the part this way and move on to a bigger part containing the previous one. You go back by the length of the segment you're trying at the moment and check if using this segment plus the weight of the previously build part will make up to better sum of the weight for the current part.
Supposedly, the cutting wood problem is no different, but you add the 2-dimension, additional loop somewhere in the middle. Unfortunately, I can't imagine how to store the values and how to go back for the 2-dimensions.
I've tried doing like:
1. Loop on one dimension
2. Loop on second dimension
3. Loop on all the segments you can use
4. Check if you can fit the current segment depending on 1. and 2.
5. If yes, go back the length of the segment to see if weight of the segment + what's stored there gives you a greater result; do the same for the width
6. Store the result in the cell you're currently on
7. Go through the array and find the greatest result
Here is the code I produced after many debugging tries:
public int Cut((int length, int width) sheet, (int length, int width, int price)[] elements, out Cut cuts)
{
int[,] tmpSheetArr = new int[sheet.length + 1, sheet.width + 1];
for (int i = 1; i < tmpSheetArr.GetLength(0); i++)
{
for (int j = 1; j < tmpSheetArr.GetLength(1); j++)
{
tmpSheetArr[i, j] = Int32.MinValue;
}
}
for (int i = 1; i < tmpSheetArr.GetLength(0); i++) //columns
{
for (int j = 1; j < tmpSheetArr.GetLength(1); j++) //rows
{
for (int e = 0; e < elements.Length; e++)
{
(int length, int width, int price) elem = elements[e];
if (i >= elem.length && j >= elem.width)
{
int tmpJ, tmpI, tmpVal;
tmpJ = j - elem.width;
tmpI = i;
while (0 < tmpI)
{
if(tmpI > i - elem.length && tmpI <= i && tmpJ > j - elem.width && tmpJ <= j)
{
tmpJ -= 1;
if (-1 == tmpJ)
{
tmpJ = tmpSheetArr.GetLength(1) - 1;
tmpI -= 1;
}
continue;
}
tmpVal = tmpSheetArr[tmpI, tmpJ] == Int32.MinValue ? 0 : tmpSheetArr[tmpI, tmpJ];
if (tmpSheetArr[i, j] < elem.price + tmpVal)
{
tmpSheetArr[i, j] = elem.price + tmpVal;
}
tmpJ -= 1;
if(-1 == tmpJ)
{
tmpJ = tmpSheetArr.GetLength(1) - 1;
tmpI -= 1;
}
}
}
}
}
}
int tmpMax = 0;
for (int i = 1; i < tmpSheetArr.GetLength(0); i++)
{
for (int j = 1; j < tmpSheetArr.GetLength(1); j++)
{
if (tmpMax < tmpSheetArr[i, j])
tmpMax = tmpSheetArr[i, j];
}
}
cuts = null;
return tmpMax;
}
It doesn't work, gives too big results in some cases and gets stuck on bigger problems. I think the main problem is about going back - with only the weight stored I don't know what size of the block was used and if it will overlap with the current one.
I decided to write it from the beginning, but really can't find another approach. I have a code for the 1D problem:
int cutRod(int[] price, int n)
{
int[] val = new int[n + 1];
val[0] = 0;
int i, j;
// Build the table val[] and return the last entry
// from the table
for (i = 1; i <= n; i++)
{
int max_val = Int32.MinValue;
for (j = 0; j < i; j++)
max_val = Math.Max(max_val, price[j] + val[i - j - 1]);
val[i] = max_val;
}
return val[n];
}
How do I change it so it works for 2D problem?
I tried to explain my limited understanding and way of thinking the best I could. I would appreciate any help on this matter.
Make your dynamic state at x be a dictionary mapping a particular "skyline" of what blocks placed before x look like after x. You start with a flat skyline (no blocks so far, clean edge), and you're looking for a flat skyline at the other end (didn't go off the edge of the sheet).
As you advance you "lower" your skyline by 1, start looking at ways to cut out new blocks, and get new possible skylines.
The number of possible skylines will grow exponentially with the width of the rectangle.
The solution:
Build an array of maximum values that can be obtained from given piece of dimensions 1x1 up to the size of the board. Maximum value for given piece is stored under index of [(length of the piece) - 1, (width of the piece) - 1]. To find the maximum value, check how the current piece can be formed with previous pieces and cuts.
To construct the tree of cuts, build a second array of the best cuts for the current piece. Root of the cuts tree for the current piece is stored under index of [(length of the piece) - 1, (width of the piece) - 1].
Cuts class:
public class Cut
{
public int length; // vertical dimension (before cut)
public int width; // horizontal dimension (before cut)
public int price; // sum of the values of the two elements resulting from the cut
public bool vertical; // true for vertical cut, false otherwise
public int n; // distance from left side (for vertical cut) or top (for horizontal cut) of the current piece
// price 0 means there was no cut, topleft and bottomright are null,
public Cut topleft; // top/left resulting piece after cut
public Cut bottomright; // bottom/right resulting piece after cut
public Cut(int length, int width, int price, bool vertical=true, int n=0, Cut topleft=null, Cut bottomright=null)
{
this.length = length;
this.width = width;
this.price = price;
this.vertical = vertical;
this.n = n;
this.topleft = topleft;
this.bottomright = bottomright;
}
}
Function finding the maximum value and a tree of cuts:
public int Cut((int length, int width) sheet, (int length, int width, int price)[] elements, out Cut cuts)
{
int[,] sheetArr = new int[sheet.length, sheet.width]; //contains best values of current pieces that can be formed
Cut[,] cutsArr = new Cut[sheet.length, sheet.width]; //contains references for cuts used to form pieces of the best value,
for (int l = 0; l < sheet.length; l++) //loop on length
{
for (int w = 0; w < sheet.width; w++) //loop on width
{
foreach ((int length, int width, int price) elem in elements) //loop on elements
{
if (elem.length == l + 1 && elem.width == w + 1) //check if current piece can be build with one of the given elements
{
sheetArr[l, w] = elem.price;
cutsArr[l, w] = new Cut(elem.length, elem.width, elem.price); //piece is exactly one of the elements (no cut)
break; //no 2 elements of the same size in the given elements
}
cutsArr[l, w] = new Cut(l + 1, w + 1, 0); //piece can not be formed from given elements, price = 0 (no cut)
}
for (int i = 1; i < Math.Floor((decimal)(l + 1) / 2) + 1; i++) //go back on length
{
if (sheetArr[i - 1, w] + sheetArr[l - i, w] > sheetArr[l, w])
{
sheetArr[l, w] = sheetArr[i - 1, w] + sheetArr[l - i, w];
cutsArr[l, w] = new Cut(l + 1, w + 1, sheetArr[l, w], false, i, cutsArr[i - 1, w], cutsArr[l - i, w]);
}
}
for (int i = 1; i < Math.Floor((decimal)(w + 1) / 2) + 1; i++) //go back on width
{
if (sheetArr[l, i - 1] + sheetArr[l, w - i] > sheetArr[l, w])
{
sheetArr[l, w] = sheetArr[l, i - 1] + sheetArr[l, w - i];
cutsArr[l, w] = new Cut(l + 1, w + 1, sheetArr[l, w], true, i, cutsArr[l, i - 1], cutsArr[l, w - i]);
}
}
}
}
cuts = cutsArr[sheet.length - 1, sheet.width - 1];
return sheetArr[sheet.length - 1, sheet.width - 1];
}
I'm looking for an algorithm which computes all permutations of a bitstring of given length (n) and amount of bits set (k). For example while n=4 and k=2 the algorithm shall output:
1100
1010
1001
0011
0101
0110
I'm aware of Gosper's Hack which generates the needed permutations in lexicographic order. But i need them to be generated in such a manner, that two consecutive permutations differ in only two (or at least a constant number of) bitpositions (like in the above example).
Another bithack to do that would be awesome, but also a algorithmic description would help me alot.
Walking bit algorithm
To generate permutations of a binary sequence by swapping exactly one set bit with an unset bit in each step (i.e. the Hamming distance between consecutive permutations equals two), you can use this "walking bit" algorithm; the way it works is similar to creating the (reverse) lexicographical order, but the set bits walk right and left alternately, and as a result some parts of the sequence are mirrored. This is probably better explained with an example:
Recursive implementation
A recursive algorithm would receive a sequence of n bits, with k bits set, either all on the left or all on the right. It would then keep a 1 at the end, recurse with the rest of the sequence, move the set bit and keep 01 at the end, recurse with the rest of the bits, move the set bit and keep 001 at the end, etc... until the last recursion with only set bits. As you can see, this creates alternating left-to-right and right-to-left recursions.
When the algorithm is called with a sequence with only one bit set, this is the deepest recursion level, and the set bit walks from one end to the other.
Code example 1
Here's a simple recursive JavaScript implementation:
function walkingBits(n, k) {
var seq = [];
for (var i = 0; i < n; i++) seq[i] = 0;
walk (n, k, 1, 0);
function walk(n, k, dir, pos) {
for (var i = 1; i <= n - k + 1; i++, pos += dir) {
seq[pos] = 1;
if (k > 1) walk(n - i, k - 1, i%2 ? dir : -dir, pos + dir * (i%2 ? 1 : n - i))
else document.write(seq + "<BR>");
seq[pos] = 0;
}
}
}
walkingBits(7,3);
Translated into C++ that could be something like this:
#include <iostream>
#include <string>
void walkingBits(int n, int k, int dir = 1, int pos = 0, bool top = true) {
static std::string seq;
if (top) seq.resize(n, '0');
for (int i = 1; i <= n - k + 1; i++, pos += dir) {
seq[pos] = '1';
if (k > 1) walkingBits(n - i, k - 1, i % 2 ? dir : -dir, pos + dir * (i % 2 ? 1 : n - i), false);
else std::cout << seq << '\n';
seq[pos] = '0';
}
if (top) seq.clear();
}
int main() {
walkingBits(7, 3);
}
(See also [this C++11 version][3], written by VolkerK in response to a question about the above code.)
(Rextester seems to have been hacked, so I've pasted Volker's code below.)
#include <iostream>
#include <vector>
#include <functional>
void walkingBits(size_t n, size_t k) {
std::vector<bool> seq(n, false);
std::function<void(const size_t, const size_t, const int, size_t)> walk = [&](const size_t n, const size_t k, const int dir, size_t pos){
for (size_t i = 1; i <= n - k + 1; i++, pos += dir) {
seq[pos] = true;
if (k > 1) {
walk(n - i, k - 1, i % 2 ? dir : -dir, pos + dir * (i % 2 ? 1 : n - i));
}
else {
for (bool v : seq) {
std::cout << v;
}
std::cout << std::endl;;
}
seq[pos] = false;
}
};
walk(n, k, 1, 0);
}
int main() {
walkingBits(7, 3);
return 0;
}
Code example 2
Or, if you prefer code where elements of an array are actually being swapped:
function walkingBits(n, k) {
var seq = [];
for (var i = 0; i < n; i++) seq[i] = i < k ? 1 : 0;
document.write(seq + "<BR>");
walkRight(n, k, 0);
function walkRight(n, k, pos) {
if (k == 1) for (var p = pos + 1; p < pos + n; p++) swap(p - 1, p)
else for (var i = 1; i <= n - k; i++) {
[walkLeft, walkRight][i % 2](n - i, k - 1, pos + i);
swap(pos + i - 1, pos + i + (i % 2 ? 0 : k - 1));
}
}
function walkLeft(n, k, pos) {
if (k == 1) for (var p = pos + n - 1; p > pos; p--) swap(p - 1, p)
else for (var i = 1; i <= n - k; i++) {
[walkRight, walkLeft][i % 2](n - i, k - 1, pos);
swap(pos + n - i - (i % 2 ? 1 : k), pos + n - i);
}
}
function swap(a, b) {
var c = seq[a]; seq[a] = seq[b]; seq[b] = c;
document.write(seq + "<BR>");
}
}
walkingBits(7,3);
Code example 3
Here the recursion is rolled out into an iterative implementation, with each of the set bits (i.e. each of the recursion levels) represented by an object {o,d,n,p} which holds the offset from the leftmost position, the direction the set bit is moving in, the number of bits (i.e. the length of this part of the sequence), and the current position of the set bit within this part.
function walkingBits(n, k) {
var b = 0, seq = [], bit = [{o: 0, d: 1, n: n, p: 0}];
for (var i = 0; i < n; i++) seq.push(0);
while (bit[0].p <= n - k) {
seq[bit[b].o + bit[b].p * bit[b].d] = 1;
while (++b < k) {
bit[b] = {
o: bit[b-1].o + bit[b-1].d * (bit[b-1].p %2 ? bit[b-1].n-1 : bit[b-1].p+1),
d: bit[b-1].d * (bit[b-1].p %2 ? -1 : 1),
n: bit[b-1].n - bit[b-1].p - 1,
p: 0
}
seq[bit[b].o + bit[b].p * bit[b].d] = 1;
}
document.write(seq + "<BR>");
b = k - 1;
do seq[bit[b].o + bit[b].p * bit[b].d] = 0;
while (++bit[b].p > bit[b].n + b - k && b--);
}
}
walkingBits(7, 3); // n >= k > 0
Transforming lexicographical order into walking bit
Because the walking bit algorithm is a variation of the algorithm to generate the permutations in (reverse) lexicographical order, each permutation in the lexicographical order can be transformed into its corresponding permutation in the walking bit order, by mirroring the appropriate parts of the binary sequence.
So you can use any algorithm (e.g. Gosper's Hack) to create the permutations in lexicographical or reverse lexicographical order, and then transform each one to get the walking bit order.
Practically, this means iterating over the binary sequence from left to right, and if you find a set bit after an odd number of zeros, reversing the rest of the sequence and iterating over it from right to left, and so on...
Code example 4
In the code below the permutations for n,k = 7,3 are generated in reverse lexicographical order, and then transformed one-by-one:
function lexi2walk(lex) {
var seq = [], ofs = 0, pos = 0, dir = 1;
for (var i = 0; i < lex.length; ++i) {
if (seq[ofs + pos * dir] = lex[i]) {
if (pos % 2) ofs -= (dir *= -1) * (pos + lex.length - 1 - i)
else ofs += dir * (pos + 1);
pos = 0;
} else ++pos;
}
return seq;
}
function revLexi(seq) {
var max = true, pos = seq.length, set = 1;
while (pos-- && (max || !seq[pos])) if (seq[pos]) ++set; else max = false;
if (pos < 0) return false;
seq[pos] = 0;
while (++pos < seq.length) seq[pos] = set-- > 0 ? 1 : 0;
return true;
}
var s = [1,1,1,0,0,0,0];
document.write(s + " → " + lexi2walk(s) + "<br>");
while (revLexi(s)) document.write(s + " → " + lexi2walk(s) + "<br>");
Homogeneous Gray path
The permutation order created by this algorithm is similar, but not identical, to the one created by the "homogeneous Gray path for combinations" algorithm described by D. Knuth in The Art of Computer Programming vol. 4a, sect. 7.2.1.3, formula (31) & fig. 26c.
This is easy to achieve with recursion:
public static void nextPerm(List<Integer> list, int num, int index, int n, int k) {
if(k == 0) {
list.add(num);
return;
}
if(index == n) return;
int mask = 1<<index;
nextPerm(list, num^mask, index+1, n, k-1);
nextPerm(list, num, index+1, n, k);
}
Running this with the client:
public static void main(String[] args) {
ArrayList<Integer> list = new ArrayList<Integer>();
nextPerm(list, 0, 0, 4, 2);
}
Output:
0011
0101
1001
0110
1010
1100
The idea is to start with the initial number, and consider changing a bit, one index at a time, and to keep track of how many times you changed the bits. Once you changed the bits k times (when k == 0), store the number and terminate the branch.
Question is such that given a set of numbers we have to write a recursive program which prints all possible combination after pairing consecutive numbers or leaving them single.
<div>
Ex set 1,2,3,4,5,6
Output
<ul>
<li>1,2,3,4,5,6</li>
<li>12,3,4,5,6</li>
<li>1,23,4,5,6</li>
<li>1,2,34,5,6</li>
<li>1,2,3,45,6</li>
<li>1,2,3,4,56</li>
<li>12,34,5,6</li>
<li>12,3,45,6</li>
<li>12,3,4,56</li>
<li>1,23,45,6</li>
<li>1,23,4,56</li>
<li>1,2,34,56</li>
<li>12,34,56</li>
</div>
I use c++ to code.
Suppose the given set is a(a[0], a[1], ..., a[n - 1]), and the length of a is n
And the current answer is saved in b
void dfs(int pos, int depth)
{
if(pos >= n)
for(int i = 0; i < depth; ++i)
printf("%d%c", b[i], i == depth - 1 ? '\n' : ',');
else
{
b[depth] = a[pos];
dfs(pos + 1, depth + 1);
if(pos + 1 < n)
{
int c = 1, x = a[pos];
while(x) c *= 10, x /= 10;
b[depth] = a[pos] * c + a[pos + 1];
dfs(pos + 2, depth + 1);
}
}
}
Is there a way to find a number of rectangular submatrices containing all zeros with a complexity smaller than O(n^3), where n is the dimension of given matrix?
Here is a solution O(n² log n).
First, let's convert the main problem to something like this:
For given histogram, find the number of submatrices containing all zeros.
How to convert it ?
For each position calculate the height of column that start on that position and contain only zeros.
Example:
10010 01101
00111 12000
00001 -> 23110
01101 30020
01110 40001
It can be easily find in O(n²).
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
up[i][j] = arr[i][j] ? 0 : 1 + up[i - 1][j];
Now we can consider each row as histogram with given heights.
Let's solve the problem with histogram.
Our goal is to travel all heights from left to right, and on each step we are going to update array L.
This array for each height is going to contain maximum widths so that we can make a rectangle of this width from current position, to the left and of given height.
Consider example:
0
0 0
0 000
00000 -> heights: 6 3 4 4 5 2
000000
000000
L[6]: 1 0 0 0 0 0
L[5]: 1 0 0 0 1 0
L[4]: 1 0 1 2 3 0
L[3]: 1 2 3 4 5 0
L[2]: 1 2 3 4 5 6
L[1]: 1 2 3 4 5 6
steps: 1 2 3 4 5 6
As you can see if we add all those numbers we will receive an answer for given histogram.
We can simply update array L in O(n), however we can also do it in O(log n) by using segment tree (with lazy propagation) that can add in interval, set value in interval and get sum from interval.
In each step we just add 1 to interval [1, height] and set 0 in interval[height + 1, maxHeight] and get sum from interval [1, maxHeight].
height - height of current column in histogram.
maxHeight - maximum height of column in histogram.
And thats how you can get O(n² * log n) solution :)
Here is main code in C++:
const int MAXN = 1000;
int n;
int arr[MAXN + 5][MAXN + 5]; // stores given matrix
int up[MAXN + 5][MAXN + 5]; // heights of columns of zeros
long long answer;
long long calculate(int *h, int maxh) { // solve it for histogram
clearTree();
long long result = 0;
for(int i = 1; i <= n; i++) {
add(1, h[i]); // add 1 to [1, h[i]]
set(h[i] + 1, maxh); // set 0 in [h[i] + 1, maxh];
result += query(); // get sum from [1, maxh]
}
return result;
}
int main() {
ios_base::sync_with_stdio(0);
cin >> n;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
cin >> arr[i][j]; // read the data
for(int i = 1; i <= n; i++)
for(int j = 1; j <= n; j++)
up[i][j] = arr[i][j] ? 0 : 1 + up[i - 1][j]; // calculate values of up
for(int i = 1; i <= n; i++)
answer += calculate(up[i], i); // calculate for each row
cout << answer << endl;
}
Here is the beginning of code, segment tree:
#include <iostream>
using namespace std;
// interval-interval tree that stores sums
const int p = 11;
int sums[1 << p];
int lazy[1 << p];
int need[1 << p];
const int M = 1 << (p - 1);
void update(int node) {
if(need[node] == 1) { // add
sums[node] += lazy[node];
if(node < M) {
need[node * 2] = need[node * 2] == 2 ? 2 : 1;
need[node * 2 + 1] = need[node * 2 + 1] == 2 ? 2 : 1;
lazy[node * 2] += lazy[node] / 2;
lazy[node * 2 + 1] += lazy[node] / 2;
}
} else if(need[node] == 2) { // set
sums[node] = lazy[node];
if(node < M) {
need[node * 2] = need[node * 2 + 1] = 2;
lazy[node * 2] = lazy[node] / 2;
lazy[node * 2 + 1] = lazy[node] / 2;
}
}
need[node] = 0;
lazy[node] = 0;
}
void insert(int node, int l, int r, int lq, int rq, int value, int id) {
update(node);
if(lq <= l && r <= rq) {
need[node] = id;
lazy[node] = value * (r - l + 1);
update(node);
return;
}
int mid = (l + r) / 2;
if(lq <= mid) insert(node * 2, l, mid, lq, rq, value, id);
if(mid + 1 <= rq) insert(node * 2 + 1, mid + 1, r, lq, rq, value, id);
sums[node] = sums[node * 2] + sums[node * 2 + 1];
}
int query() {
return sums[1]; // we only need to know sum of the whole interval
}
void clearTree() {
for(int i = 1; i < 1 << p; i++)
sums[i] = lazy[i] = need[i] = 0;
}
void add(int left, int right) {
insert(1, 0, M - 1, left, right, 1, 1);
}
void set(int left, int right) {
insert(1, 0, M - 1, left, right, 0, 2);
}
// end of the tree
Can you please help me solving this one?
You have an unordered array X of n integers. Find the array M containing n elements where Mi is the product of all integers in X except for Xi. You may not use division. You can use extra memory. (Hint: There are solutions faster than O(n^2).)
The basic ones - O(n^2) and one using division is easy. But I just can't get another solution that is faster than O(n^2).
Let left[i] be the product of all elements in X from 1..i. Let right[i] be the product of all elements in X from i..N. You can compute both in O(n) without division in the following way: left[i] = left[i - 1] * X[i] and right[i] = right[i + 1] * X[i];
Now we will compute M: M[i] = left[i - 1] * right[i + 1]
Note: left and right are arrays.
Hope it is clear:)
Here's a solution in Python. I did the easy way with division to compare against the hard way without. Do I get the job?
L = [2, 1, 3, 5, 4]
prod = 1
for i in L: prod *= i
easy = map(lambda x: prod/x, L)
print easy
hard = [1]*len(L)
hmm = 1
for i in range(len(L) - 1):
hmm *= L[i]
hard[i + 1] *= hmm
huh = 1
for i in range(len(L) - 1, 0, -1):
huh *= L[i]
hard[i - 1] *= huh
print hard
O(n) - http://nbl.cewit.stonybrook.edu:60128/mediawiki/index.php/TADM2E_3.28
two passes -
int main (int argc, char **argv) {
int array[] = {2, 5, 3, 4};
int fwdprod[] = {1, 1, 1, 1};
int backprod[] = {1, 1, 1, 1};
int mi[] = {1, 1, 1, 1};
int i, n = 4;
for (i=1; i<=n-1; i++) {
fwdprod[i]=fwdprod[i-1]*array[i-1];
}
for (i=n-2; i>=0; i--) {
backprod[i] = backprod[i+1]*array[i+1];
}
for (i=0;i<=n-1;i++) {
mi[i]=fwdprod[i]*backprod[i];
}
return 0;
}
Old but very cool, I've been asked this at an interview myself and seen several solutions since but this is my favorite as taken from
http://www.polygenelubricants.com/2010/04/on-all-other-products-no-division.html
static int[] products(int... nums) {
final int N = nums.length;
int[] prods = new int[N];
java.util.Arrays.fill(prods, 1);
for (int // pi----> * <----pj
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 ;
System.out.println("pi up to this point is " + pi + "\n");
System.out.println("pj up to this point is " + pj + "\n");
System.out.println("prods[i]:" + prods[i] + "pros[j]:" + prods[j] + "\n");
}
return prods;
}
Here's what's going on, if you write out prods[i] for all the iterations, you'll see the following being calculated
prods[0], prods[n-1]
prods[1], prods[n-2]
prods[2], prods[n-3]
prods[3], prods[n-4]
.
.
.
prods[n-3], prods[2]
prods[n-2], prods[1]
prods[n-1], prods[0]
so each prods[i] get hit twice, one from the going from head to tail and once from tail to head, and both of these iterations are accumulating the product as they
traverse towards the center so it's easy to see we'll get exactly what we need, we just need to be careful and see that it misses the element itself and that's where
it gets tricky. the key lies in the
pi *= nums[i++], pj *= nums[j--]
in the for loop conditional itself and not in the body which do not happen until the end of the
iteration. so for
prods[0],
it starts at 1*1 and then pi gets set to 120 after, so prods[0] misses the first elements
prods[1], it's 1 * 120 = 120 and then pi gets set to 120*60 after
so on and so on
O(nlogn) approach:
int multiply(int arr[], int start, int end) {
int mid;
if (start > end) {
return 1;
}
if (start == end) {
return arr[start];
}
mid = (start+end)/2;
return (multiply(arr, start, mid)*multiply(arr, mid+1, end));
}
int compute_mi(int arr[], int i, int n) {
if ((i >= n) || (i < 0)) {
return 0;
}
return (multiply(arr, 0, i-1)*multiply(arr, i+1, n-1));
}
Here is my solution in Python: Easy way but with high computational cost may be?
def product_list(x):
ans = [p for p in range(len(x))]
for i in range(0, len(x)):
a = 1
for j in range(0, len(x)):
if i != j:
a = a*x[j]
ans[i] = a
return ans