Counting tilings of a rectangle - logic

I am trying to solve this problem but I can't find a solution:
A board consisting of squares arranged into N rows and M columns is given. A tiling of this board is a pattern of tiles that covers it. A tiling is interesting if:
only tiles of size 1x1 and/or 2x2 are used;
each tile of size 1x1 covers exactly one whole square;
each tile of size 2x2 covers exactly four whole squares;
each square of the board is covered by exactly one tile.
For example, the following images show a few interesting tilings of a board of size 4 rows and 3 columns:
http://dabi.altervista.org/images/task.img.4x3_tilings_example.gif
Two interesting tilings of a board are different if there exists at least one square on the board that is covered with a tile of size 1x1 in one tiling and with a tile of size 2x2 in the other. For example, all tilings shown in the images above are different.
Write a function
int count_tilings(int N, int M);
that, given two integers N and M, returns the remainder modulo 10,000,007 of the number of different interesting tilings of a board of size N rows and M columns.
Assume that:
N is an integer within the range [1..1,000,000];
M is an integer within the range [1..7].
For example, given N = 4 and M = 3, the function should return 11, because there are 11 different interesting tilings of a board of size 4 rows and 3 columns:
http://dabi.altervista.org/images/task.img.4x3_tilings_all.gif
for (4,3) the result is 11, for (6,5) the result is 1213.
I tried the following but it doesn't work:
static public int count_tilings ( int N,int M ) {
int result=1;
if ((N==1)||(M==1)) return 1;
result=result+(N-1)*(M-1);
int max_tiling= (int) ((int)(Math.ceil(N/2))*(Math.ceil(M/2)));
System.out.println(max_tiling);
for (int i=2; i<=(max_tiling);i++){
if (N>=2*i){
int n=i+(N-i);
int k=i;
//System.out.println("M-1->"+(M-1) +"i->"+i);
System.out.println("(M-1)^i)->"+(Math.pow((M-1),i)));
System.out.println( "n="+n+ " k="+k);
System.out.println(combinations(n, k));
if (N-i*2>0){
result+= Math.pow((M-1),i)*combinations(n, k);
}else{
result+= Math.pow((M-1),i);
}
}
if (M>=2*i){
int n=i+(M-i);
int k=i;
System.out.println("(N-1)^i)->"+(Math.pow((N-1),i)));
System.out.println( "n="+n+ " k="+k);
System.out.println(combinations(n, k));
if (M-i*2>0){
result+= Math.pow((N-1),i)*combinations(n, k);
}else{
result+= Math.pow((N-1),i);
}
}
}
return result;
}
static long combinations(int n, int k) {
/*binomial coefficient*/
long coeff = 1;
for (int i = n - k + 1; i <= n; i++) {
coeff *= i;
}
for (int i = 1; i <= k; i++) {
coeff /= i;
}
return coeff;
}

Since this is homework I won't give a full solution, but I'll give you some hints.
First here's a recursive solution:
class Program
{
// Important note:
// The value of masks given here is hard-coded for m == 5.
// In a complete solution, you need to calculate the masks for the
// actual value of m given. See explanation in answer for more details.
int[] masks = { 0, 3, 6, 12, 15, 24, 27, 30 };
int CountTilings(int n, int m, int s = 0)
{
if (n == 1) { return 1; }
int result = 0;
foreach (int mask in masks)
{
if ((mask & s) == 0)
{
result += CountTilings(n - 1, m, mask);
}
}
return result;
}
public static void Main()
{
Program p = new Program();
int result = p.CountTilings(6, 5);
Console.WriteLine(result);
}
}
See it working online: ideone
Note that I've added an extra parameter s. This stores the contents of the first column. If the first column is empty, s = 0. If the first column contains some filled squares the corresponding bits in s are set. Initially s = 0, but when a 2 x 2 tile is placed, this fills up some squares in the next column, and that will mean that s will be non-zero in the recursive call.
The masks variable is hard-coded but in a complete solution it needs to be calculated based on the actual value of m. The values stored in masks make more sense if you look at their binary representations:
00000
00011
00110
01100
01111
11000
11011
11110
In other words, it's all the ways of setting pairs of bits in a binary number with m bits. You can write some code to generate all these possiblities. Or since there are only 7 possible values of m, you could also just hard-code all seven possibilities for masks.
There are however two serious problems with the recursive solution.
It will overflow the stack for large values of N.
It requires exponential time to calculate. It is incredibly slow even for small values of N
Both these problems can be solved by rewriting the algorithm to be iterative. Keep m constant and initalize the result for n = 1 for all possible values of s to be 1. This is because if you only have one column you must use only 1x1 tiles, and there is only one way to do this.
Now you can calculate n = 2 for all possible values of s by using the results from n = 1. This can be repeated until you reach n = N. This algorithm completes in linear time with respect to N, and requires constant space.

Here is a recursive solution:
// time used : 27 min
#include <set>
#include <vector>
#include <iostream>
using namespace std;
void placement(int n, set< vector <int> > & p){
for (int i = 0; i < n -1 ; i ++){
for (set<vector<int> > :: iterator j = p.begin(); j != p.end(); j ++){
vector <int> temp = *j;
if (temp[i] == 1 || temp[i+1] == 1) continue;
temp[i] = 1; temp[i+1] = 1;
p.insert(temp);
}
}
}
vector<vector<int> > placement( int n){
if (n > 7) throw "error";
set <vector <int> > p;
vector <int> temp (n,0);
p.insert (temp);
for (int i = 0; i < 3; i ++) placement(n, p);
vector <vector <int> > s;
s.assign (p.begin(), p.end());
return s;
}
bool tryput(vector <vector <int> > &board, int current, vector<int> & comb){
for (int i = 0; i < comb.size(); i ++){
if ((board[current][i] == 1 || board[current+1][i]) && comb[i] == 1) return false;
}
return true;
}
void put(vector <vector <int> > &board, int current, vector<int> & comb){
for (int i = 0; i < comb.size(); i ++){
if (comb[i] == 1){
board[current][i] = 1;
board[current+1][i] = 1;
}
}
return;
}
void undo(vector <vector <int> > &board, int current, vector<int> & comb){
for (int i = 0; i < comb.size(); i ++){
if (comb[i] == 1){
board[current][i] = 0;
board[current+1][i] = 0;
}
}
return;
}
int place (vector <vector <int> > &board, int current, vector < vector <int> > & all_comb){
int m = board.size();
if (current >= m) throw "error";
if (current == m - 1) return 1;
int count = 0;
for (int i = 0; i < all_comb.size(); i ++){
if (tryput(board, current, all_comb[i])){
put(board, current, all_comb[i]);
count += place(board, current+1, all_comb) % 10000007;
undo(board, current, all_comb[i]);
}
}
return count;
}
int place (int m, int n){
if (m == 0) return 0;
if (m == 1) return 1;
vector < vector <int> > all_comb = placement(n);
vector <vector <int> > board(m, vector<int>(n, 0));
return place (board, 0, all_comb);
}
int main(){
cout << place(3, 4) << endl;
return 0;
}
time complexity O(n^3 * exp(m))
to reduce the space usage try bit vector.
to reduce the time complexity to O(m*(n^3)), try dynamic programming.
to reduce the time complexity to O(log(m) * n^3) try divide and conquer + dynamic programming.
good luck

Related

Is every recursive algorithm a divide and conquer algorithm?

I have a problem for homework and I need to solve this problem with a divide and conquer algorithm.
I solved this algorithm by using recursion. Did I use divide and conquer automatically by using recursion?
For example, is this below approach a divide an conquer algorithm? Because I use fun function in fun.(recursive call)
Code:
#include <stdio.h>
/* int a[] = {-6,60,-10,20}; */
int a[] = {-2, -3, 4, -1, -2, 1, 5, -3};
int len = sizeof(a)/sizeof(*a);
int maxherearray[10];
int fun(int n);
int max(int a, int b);
int find_max(int a[], int len);
void print_array(int a[], int start_idx, int end_idx);
int start_idx = 0; // Start of contiguous subarray giving max sum
int end_idx = 0; // End of contiguous subarray giving max sum
#define NEG_INF (-100000)
int max_sum = NEG_INF; // The max cont sum seen so far.
int main(void)
{
start_idx = 0;
end_idx = len - 1;
maxherearray[0] = a[0];
printf("Array a[]: ");
print_array(a, 0, len-1);
printf("\n");
// Compute the necessary information to get max contiguous subarray
fun(len - 1);
printf("Max subarray value == %d\n", find_max(maxherearray, len));
printf("\n");
printf("Contiguous sums: ");
print_array(maxherearray, 0, len - 1);
printf("\n");
printf("Contiguous subarray giving max sum: ");
print_array(a, start_idx, end_idx);
printf("\n\n");
return 0;
}
int fun(int n)
{
if(n==0)
return a[0];
int max_till_j = fun(n - 1);
// Start of new contiguous sum
if (a[n] > a[n] + max_till_j)
{
maxherearray[n] = a[n];
if (maxherearray[n] > max_sum)
{
start_idx = end_idx = n;
max_sum = maxherearray[n];
}
}
// Add to current contiguous sum
else
{
maxherearray[n] = a[n] + max_till_j;
if (maxherearray[n] > max_sum)
{
end_idx = n;
max_sum = maxherearray[n];
}
}
return maxherearray[n];
}
int max(int a, int b)
{
return (a > b)? a : b;
}
// Print subarray a[i] to a[j], inclusive of end points.
void print_array(int a[], int i, int j)
{
for (; i <= j; ++i) {
printf("%d ", a[i]);
}
}
int find_max(int a[], int len)
{
int i;
int max_val = NEG_INF;
for (i = 0; i < len; ++i)
{
if (a[i] > max_val)
{
max_val = a[i];
}
}
return max_val;
}
Every recursion function is not necessarily divide-and-conquer approach. There are other approaches like decrease-and-conquer(decrease by a constant factor, decrease by one, variable-size decrease).
Is this below approach a divide an conquer algorithm?
Your function is exactly decrease by a constant factor which is 1 approach. You can glance at here.
Pseudocode for the divide-and-conquer algorithm for
finding a maximum-subarray
MaxSubarray(A,low,high)
//
if high == low
return (low, high, A[low]) // base case: only one element
else
// divide and conquer
mid = floor( (low + high)/2 )
(leftlow,lefthigh,leftsum) = MaxSubarray(A,low,mid)
(rightlow,righthigh,rightsum) = MaxSubarray(A,mid+1,high)
(xlow,xhigh,xsum) = MaxXingSubarray(A,low,mid,high)
// combine
if leftsum >= rightsum and leftsum >= xsum
return (leftlow,lefthigh,leftsum)
else if rightsum >= leftsum and rightsum >= xsum
return (rightlow,righthigh,rightsum)
else
return (xlow,xhigh,xsum)
end if
end if
--------------------------------------------------------------
MaxXingSubarray(A,low,mid,high)
// Find a max-subarray of A[i..mid]
leftsum = -infty
sum = 0
for i = mid downto low
sum = sum + A[i]
if sum > leftsum
leftsum = sum
maxleft = i
end if
end for
// Find a max-subarray of A[mid+1..j]
rightsum = -infty
sum = 0
for j = mid+1 to high
sum = sum + A[j]
if sum > rightsum
rightsum = sum
maxright = j
end if
end for
// Return the indices i and j and the sum of the two subarrays
return (maxleft,maxright,leftsum + rightsum)
-----------------------------------------------------------
=== Remarks:
(1) Initial call: MaxSubarray(A,1,n)
(2) Divide by computing mid.
Conquer by the two recursive alls to MaxSubarray.
Combine by calling MaxXingSubarray and then determining
which of the three results gives the maximum sum.
(3) Base case is when the subarray has only 1 element.
Not necessarily. If you explore the functional programming paradigm you will learn that the simple for loop can be replaced with recursion
for i in range(x):
body(i)
changes to
def do_loop(x, _start=0):
if _start < x:
body(_start)
do_loop(x, _start=_start+1)
and it's quite obvious that not every iteration is a divide and conquer algorithm.

Complexity of backtracking algorithm

I tried to solve this problem using backtracking but I am not sure about the complexity of the algorithm (and if the algorithm is correct) and what would be an algorithm with a better complexity.
Given 2 positive integers n and m, we call legal a sequence of integers if:
the length of the sequence is n
the elements in the sequence are between 1 and m
the element in position i of the sequence, 1 < i <= n, is a divisor of the element in position i-1
Count the number of legal sequences. Expected complexity of the algorithm is O(m² + nm)
This is my algorithm in c:
// n length of the sequence
// m maximum valid number
// l number of remaining positions in the sequence
// p previous number in the sequence
int legal(int n, int m, int l, int p) {
if (l == 0)
return 1;
int q=0;
for (int i=1; i <= m;i++) {
if (p%i == 0 || l == n)
q += legal(n,m,l-1,i);
}
return q;
}
int main() {
int n, m;
scanf("%d", &n);
scanf("%d", &m);
printf("%d\n", legal(n,m,n,0));
}
I think the complexity of my algorithm is O(nmS(n)) with S(n) = the number of legal sequences
You are correct that your program runs in the solution space of problem. For this type of problem, your solution is sub-optimal for large input (say n = m = 100). That is because the solution space grows exponentially in relation to m and n. Here is a solution that uses memoization to avoid re-computations:
#include <cstdio>
#define LIMIT 101
#define DIRTY -1
long long cache[LIMIT][LIMIT];
void clear_cache() {
for (int i = 0; i < LIMIT; i++) {
for (int j = 0; j < LIMIT; j++) {
// marked all entries in cache as dirty
cache[i][j] = DIRTY;
}
}
}
long long legal_seqs(int curr_len, int prev_num, int seq_len, int max_num) {
// base case
if (curr_len == seq_len) return 1;
// if we haven't seen this sub-problem, compute it!
// this is called memoization
if (cache[curr_len][prev_num] == DIRTY) {
long long ways = 0;
// get all multiples of prev_num
for (int next_num = 1; next_num <= max_num; next_num++) {
if (prev_num % next_num == 0) {
ways += legal_seqs(curr_len + 1, next_num, seq_len, max_num);
}
}
cache[curr_len][prev_num] = ways;
}
return cache[curr_len][prev_num];
}
int main() {
int n, m;
scanf("%d%d", &n, &m);
clear_cache();
printf("%lld\n", legal_seqs(0, 0, n, m));
}
The code above runs in the time complexity you mentioned.

Dynamic Programming Coin Change Limited Coins

Dynamic Programming Change Problem (Limited Coins).
I'm trying to create a program that takes as INPUT:
int coinValues[]; //e.g [coin1,coin2,coin3]
int coinLimit[]; //e.g [2 coin1 available,1 coin2 available,...]
int amount; //the amount we want change for.
OUTPUT:
int DynProg[]; //of size amount+1.
And output should be an Array of size amount+1 of which each cell represents the optimal number of coins we need to give change for the amount of the cell's index.
EXAMPLE: Let's say that we have the cell of Array at index: 5 with a content of 2.
This means that in order to give change for the amount of 5(INDEX), you need 2(cell's content) coins (Optimal Solution).
Basically I need exactly the output of the first array of this video(C[p])
. It's exactly the same problem with the big DIFFERENCE of LIMITED COINS.
Link to Video.
Note: See the video to understand, ignore the 2nd array of the video, and have in mind that I don't need the combinations, but the DP array, so then I can find which coins to give as change.
Thank you.
Consider the next pseudocode:
for every coin nominal v = coinValues[i]:
loop coinLimit[i] times:
starting with k=0 entry, check for non-zero C[k]:
if C[k]+1 < C[k+v] then
replace C[k+v] with C[k]+1 and set S[k+v]=v
Is it clear?
O(nk) solution from an editorial I wrote a while ago:
We start with the basic DP solution that runs in O(k*sum(c)). We have our dp array, where dp[i][j] stores the least possible number of coins from the first i denominations that sum to j. We have the following transition: dp[i][j] = min(dp[i - 1][j - cnt * value[i]] + cnt) for cnt from 0 to j / value[i].
To optimize this to an O(nk) solution, we can use a deque to memorize the minimum values from the previous iteration and make the transitions O(1). The basic idea is that if we want to find the minimum of the last m values in some array, we can maintain an increasing deque that stores possible candidates for the minimum. At each step, we pop off values at the end of the deque greater than the current value before pushing the current value into the back deque. Since the current value is both further to the right and less than the values we popped off, we can be sure they will never be the minimum. Then, we pop off the first element in the deque if it is more than m elements away. The minimum value at each step is now simply the first element in the deque.
We can apply a similar optimization trick to this problem. For each coin type i, we compute the elements of the dp array in this order: For each possible value of j % value[i] in increasing order, we process the values of j which when divided by value[i] produces that remainder in increasing order. Now we can apply the deque optimization trick to find min(dp[i - 1][j - cnt * value[i]] + cnt) for cnt from 0 to j / value[i] in constant time.
Pseudocode:
let n = number of coin denominations
let k = amount of change needed
let v[i] = value of the ith denomination, 1 indexed
let c[i] = maximum number of coins of the ith denomination, 1 indexed
let dp[i][j] = the fewest number of coins needed to sum to j using the first i coin denominations
for i from 1 to k:
dp[0][i] = INF
for i from 1 to n:
for rem from 0 to v[i] - 1:
let d = empty double-ended-queue
for j from 0 to (k - rem) / v[i]:
let currval = rem + v[i] * j
if dp[i - 1][currval] is not INF:
while d is not empty and dp[i - 1][d.back() * v[i] + rem] + j - d.back() >= dp[i - 1][currval]:
d.pop_back()
d.push_back(j)
if d is not empty and j - d.front() > c[i]:
d.pop_front()
if d is empty:
dp[i][currval] = INF
else:
dp[i][currval] = dp[i - 1][d.front() * v[i] + rem] + j - d.front()
This is what you are looking for.
Assumptions made : Coin Values are in descending order
public class CoinChangeLimitedCoins {
public static void main(String[] args) {
int[] coins = { 5, 3, 2, 1 };
int[] counts = { 2, 1, 2, 1 };
int target = 9;
int[] nums = combine(coins, counts);
System.out.println(minCount(nums, target, 0, 0, 0));
}
private static int minCount(int[] nums, int target, int sum, int current, int count){
if(current > nums.length) return -1;
if(sum == target) return count;
if(sum + nums[current] <= target){
return minCount(nums, target, sum+nums[current], current+1, count+1);
} else {
return minCount(nums, target, sum, current+1, count);
}
}
private static int[] combine(int[] coins, int[] counts) {
int sum = 0;
for (int count : counts) {
sum += count;
}
int[] returnArray = new int[sum];
int returnArrayIndex = 0;
for (int i = 0; i < coins.length; i++) {
int count = counts[i];
while (count != 0) {
returnArray[returnArrayIndex] = coins[i];
returnArrayIndex++;
count--;
}
}
return returnArray;
}
}
You can check this question: Minimum coin change problem with limited amount of coins.
BTW, I created c++ program based above link's algorithm:
#include <iostream>
#include <map>
#include <vector>
#include <algorithm>
#include <limits>
using namespace std;
void copyVec(vector<int> from, vector<int> &to){
for(vector<int>::size_type i = 0; i < from.size(); i++)
to[i] = from[i];
}
vector<int> makeChangeWithLimited(int amount, vector<int> coins, vector<int> limits)
{
vector<int> change;
vector<vector<int>> coinsUsed( amount + 1 , vector<int>(coins.size()));
vector<int> minCoins(amount+1,numeric_limits<int>::max() - 1);
minCoins[0] = 0;
vector<int> limitsCopy(limits.size());
copy(limits.begin(), limits.end(), limitsCopy.begin());
for (vector<int>::size_type i = 0; i < coins.size(); ++i)
{
while (limitsCopy[i] > 0)
{
for (int j = amount; j >= 0; --j)
{
int currAmount = j + coins[i];
if (currAmount <= amount)
{
if (minCoins[currAmount] > minCoins[j] + 1)
{
minCoins[currAmount] = minCoins[j] + 1;
copyVec(coinsUsed[j], coinsUsed[currAmount]);
coinsUsed[currAmount][i] += 1;
}
}
}
limitsCopy[i] -= 1;
}
}
if (minCoins[amount] == numeric_limits<int>::max() - 1)
{
return change;
}
copy(coinsUsed[amount].begin(),coinsUsed[amount].end(), back_inserter(change) );
return change;
}
int main()
{
vector<int> coins;
coins.push_back(20);
coins.push_back(50);
coins.push_back(100);
coins.push_back(200);
vector<int> limits;
limits.push_back(100);
limits.push_back(100);
limits.push_back(50);
limits.push_back(20);
int amount = 0;
cin >> amount;
while(amount){
vector<int> change = makeChangeWithLimited(amount,coins,limits);
for(vector<int>::size_type i = 0; i < change.size(); i++){
cout << change[i] << "x" << coins[i] << endl;
}
if(change.empty()){
cout << "IMPOSSIBE\n";
}
cin >> amount;
}
system("pause");
return 0;
}
Code in c#
private static int MinCoinsChangeWithLimitedCoins(int[] coins, int[] counts, int sum)
{
var dp = new int[sum + 1];
Array.Fill(dp, int.MaxValue);
dp[0] = 0;
for (int i = 0; i < coins.Length; i++) // n
{
int coin = coins[i];
for (int j = 0; j < counts[i]; j++) //
{
for (int s = sum; s >= coin ; s--) // sum
{
int remainder = s - coin;
if (remainder >= 0 && dp[remainder] != int.MaxValue)
{
dp[s] = Math.Min(1 + dp[remainder], dp[s]);
}
}
}
}
return dp[sum] == int.MaxValue ? -1 : dp[sum];
}

How to find the subarray that has sum closest to zero or a certain value t in O(nlogn)

Actually it is the problem #10 of chapter 8 of Programming Pearls 2nd edition. It asked two questions: given an array A[] of integers(positive and nonpositive), how can you find a continuous subarray of A[] whose sum is closest to 0? Or closest to a certain value t?
I can think of a way to solve the problem closest to 0. Calculate the prefix sum array S[], where S[i] = A[0]+A[1]+...+A[i]. And then sort this S according to the element value, along with its original index information kept, to find subarray sum closest to 0, just iterate the S array and do the diff of the two neighboring values and update the minimum absolute diff.
Question is, what is the best way so solve second problem? Closest to a certain value t? Can anyone give a code or at least an algorithm? (If anyone has better solution to closest to zero problem, answers are welcome too)
To solve this problem, you can build an interval-tree by your own,
or balanced binary search tree, or even beneficial from STL map, in O(nlogn).
Following is use STL map, with lower_bound().
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
int A[] = {10,20,30,30,20,10,10,20};
// return (i, j) s.t. A[i] + ... + A[j] is nearest to value c
pair<int, int> nearest_to_c(int c, int n, int A[]) {
map<int, int> bst;
bst[0] = -1;
// barriers
bst[-int(1e9)] = -2;
bst[int(1e9)] = n;
int sum = 0, start, end, ret = c;
for (int i=0; i<n; ++i) {
sum += A[i];
// it->first >= sum-c, and with the minimal value in bst
map<int, int>::iterator it = bst.lower_bound(sum - c);
int tmp = -(sum - c - it->first);
if (tmp < ret) {
ret = tmp;
start = it->second + 1;
end = i;
}
--it;
// it->first < sum-c, and with the maximal value in bst
tmp = sum - c - it->first;
if (tmp < ret) {
ret = tmp;
start = it->second + 1;
end = i;
}
bst[sum] = i;
}
return make_pair(start, end);
}
// demo
int main() {
int c;
cin >> c;
pair<int, int> ans = nearest_to_c(c, 8, A);
cout << ans.first << ' ' << ans.second << endl;
return 0;
}
You can adapt your method. Assuming you have an array S of prefix sums, as you wrote, and already sorted in increasing order of sum value. The key concept is to not only examine consecutive prefix sums, but instead use two pointers to indicate two positions in the array S. Written in a (slightly pythonic) pseudocode:
left = 0 # Initialize window of length 0 ...
right = 0 # ... at the beginning of the array
best = ∞ # Keep track of best solution so far
while right < length(S): # Iterate until window reaches the end of the array
diff = S[right] - S[left]
if diff < t: # Window is getting too small
if t - diff < best: # We have a new best subarray
best = t - diff
# remember left and right as well
right = right + 1 # Make window bigger
else: # Window getting too big
if diff - t < best # We have a new best subarray
best = diff - t
# remember left and right as well
left = left + 1 # Make window smaller
The complexity is bound by the sorting. The above search will take at most 2n=O(n) iterations of the loop, each with computation time bound by a constant. Note that the above code was conceived for positive t.
The code was conceived for positive elements in S, and positive t. If any negative integers crop up, you might end up with a situation where the original index of right is smaller than that of left. So you'd end up with a sub sequence sum of -t. You can check this condition in the if … < best checks, but if you only suppress such cases there, I believe that you might be missing some relevant cases. Bottom line is: take this idea, think it through, but you'll have to adapt it for negative numbers.
Note: I think that this is the same general idea which Boris Strandjev wanted to express in his solution. However, I found that solution somewhat hard to read and harder to understand, so I'm offering my own formulation of this.
Your solution for the 0 case seems ok to me. Here is my solution to the second case:
You again calculate the prefix sums and sort.
You initialize to indices start to 0 (first index in the sorted prefix array) end to last (last index of the prefix array)
you start iterating over start 0...last and for each you find the corresponding end - the last index in which the prefix sum is such that prefix[start] + prefix[end] > t. When you find that end the best solution for start is either prefix[start] + prefix[end] or prefix[start] + prefix[end - 1] (the latter taken only if end > 0)
the most important thing is that you do not search for end for each start from scratch - prefix[start] increases in value when iterating over all possible values for start, which means that in each iteration you are interested only in values <= the previous value of end.
you can stop iterating when start > end
you take the best of all values obtained for all start positions.
It can easily be proved that this will give you complexity of O(n logn) for the entire algorithm.
I found this question by accident. Although it's been a while, I just post it. O(nlogn) time, O(n) space algorithm. This is running Java code. Hope this help people.
import java.util.*;
public class FindSubarrayClosestToZero {
void findSubarrayClosestToZero(int[] A) {
int curSum = 0;
List<Pair> list = new ArrayList<Pair>();
// 1. create prefix array: curSum array
for(int i = 0; i < A.length; i++) {
curSum += A[i];
Pair pair = new Pair(curSum, i);
list.add(pair);
}
// 2. sort the prefix array by value
Collections.sort(list, valueComparator);
// printPairList(list);
System.out.println();
// 3. compute pair-wise value diff: Triple< diff, i, i+1>
List<Triple> tList = new ArrayList<Triple>();
for(int i=0; i < A.length-1; i++) {
Pair p1 = list.get(i);
Pair p2 = list.get(i+1);
int valueDiff = p2.value - p1.value;
Triple Triple = new Triple(valueDiff, p1.index, p2.index);
tList.add(Triple);
}
// printTripleList(tList);
System.out.println();
// 4. Sort by min diff
Collections.sort(tList, valueDiffComparator);
// printTripleList(tList);
Triple res = tList.get(0);
int startIndex = Math.min(res.index1 + 1, res.index2);
int endIndex = Math.max(res.index1 + 1, res.index2);
System.out.println("\n\nThe subarray whose sum is closest to 0 is: ");
for(int i= startIndex; i<=endIndex; i++) {
System.out.print(" " + A[i]);
}
}
class Pair {
int value;
int index;
public Pair(int value, int index) {
this.value = value;
this.index = index;
}
}
class Triple {
int valueDiff;
int index1;
int index2;
public Triple(int valueDiff, int index1, int index2) {
this.valueDiff = valueDiff;
this.index1 = index1;
this.index2 = index2;
}
}
public static Comparator<Pair> valueComparator = new Comparator<Pair>() {
public int compare(Pair p1, Pair p2) {
return p1.value - p2.value;
}
};
public static Comparator<Triple> valueDiffComparator = new Comparator<Triple>() {
public int compare(Triple t1, Triple t2) {
return t1.valueDiff - t2.valueDiff;
}
};
void printPairList(List<Pair> list) {
for(Pair pair : list) {
System.out.println("<" + pair.value + " : " + pair.index + ">");
}
}
void printTripleList(List<Triple> list) {
for(Triple t : list) {
System.out.println("<" + t.valueDiff + " : " + t.index1 + " , " + t.index2 + ">");
}
}
public static void main(String[] args) {
int A1[] = {8, -3, 2, 1, -4, 10, -5}; // -3, 2, 1
int A2[] = {-3, 2, 4, -6, -8, 10, 11}; // 2, 4, 6
int A3[] = {10, -2, -7}; // 10, -2, -7
FindSubarrayClosestToZero f = new FindSubarrayClosestToZero();
f.findSubarrayClosestToZero(A1);
f.findSubarrayClosestToZero(A2);
f.findSubarrayClosestToZero(A3);
}
}
Solution time complexity : O(NlogN)
Solution space complexity : O(N)
[Note this problem can't be solved in O(N) as some have claimed]
Algorithm:-
Compute cumulative array(here,cum[]) of given array [Line 10]
Sort the cumulative array [Line 11]
Answer is minimum amongst C[i]-C[i+1] , $\forall$ i∈[1,n-1] (1-based index) [Line 12]
C++ Code:-
#include<bits/stdc++.h>
#define M 1000010
#define REP(i,n) for (int i=1;i<=n;i++)
using namespace std;
typedef long long ll;
ll a[M],n,cum[M],ans=numeric_limits<ll>::max(); //cum->cumulative array
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>n; REP(i,n) cin>>a[i],cum[i]=cum[i-1]+a[i];
sort(cum+1,cum+n+1);
REP(i,n-1) ans=min(ans,cum[i+1]-cum[i]);
cout<<ans; //min +ve difference from 0 we can get
}
After more thinking on this problem, I found that #frankyym's solution is the right solution. I have made some refinements on the original solution, here is my code:
#include <map>
#include <stdio.h>
#include <algorithm>
#include <limits.h>
using namespace std;
#define IDX_LOW_BOUND -2
// Return [i..j] range of A
pair<int, int> nearest_to_c(int A[], int n, int t) {
map<int, int> bst;
int presum, subsum, closest, i, j, start, end;
bool unset;
map<int, int>::iterator it;
bst[0] = -1;
// Barriers. Assume that no prefix sum is equal to INT_MAX or INT_MIN.
bst[INT_MIN] = IDX_LOW_BOUND;
bst[INT_MAX] = n;
unset = true;
// This initial value is always overwritten afterwards.
closest = 0;
presum = 0;
for (i = 0; i < n; ++i) {
presum += A[i];
for (it = bst.lower_bound(presum - t), j = 0; j < 2; --it, j++) {
if (it->first == INT_MAX || it->first == INT_MIN)
continue;
subsum = presum - it->first;
if (unset || abs(closest - t) > abs(subsum - t)) {
closest = subsum;
start = it->second + 1;
end = i;
if (closest - t == 0)
goto ret;
unset = false;
}
}
bst[presum] = i;
}
ret:
return make_pair(start, end);
}
int main() {
int A[] = {10, 20, 30, 30, 20, 10, 10, 20};
int t;
scanf("%d", &t);
pair<int, int> ans = nearest_to_c(A, 8, t);
printf("[%d:%d]\n", ans.first, ans.second);
return 0;
}
As a side note: I agree with the algorithms provided by other threads here. There is another algorithm on top of my head recently. Make up another copy of A[], which is B[]. Inside B[], each element is A[i]-t/n, which means B[0]=A[0]-t/n, B[1]=A[1]-t/n ... B[n-1]=A[n-1]-t/n. Then the second problem is actually transformed to the first problem, once the smallest subarray of B[] closest to 0 is found, the subarray of A[] closest to t is found at the same time. (It is kinda tricky if t is not divisible by n, nevertheless, the precision has to be chosen appropriate. Also the runtime is O(n))
I think there is a little bug concerning the closest to 0 solution. At the last step we should not only inspect the difference between neighbor elements but also elements not near to each other if one of them is bigger than 0 and the other one is smaller than 0.
Sorry, I thought I am supposed to get all answers for the problem. Didn't see it only requires one.
Cant we use dynamic programming to solve this question similar to kadane's algorithm.Here is my solution to this problem.Please comment if this approach is wrong.
#include <bits/stdc++.h>
using namespace std;
int main() {
//code
int test;
cin>>test;
while(test--){
int n;
cin>>n;
vector<int> A(n);
for(int i=0;i<n;i++)
cin>>A[i];
int closest_so_far=A[0];
int closest_end_here=A[0];
int start=0;
int end=0;
int lstart=0;
int lend=0;
for(int i=1;i<n;i++){
if(abs(A[i]-0)<abs(A[i]+closest_end_here-0)){
closest_end_here=A[i]-0;
lstart=i;
lend=i;
}
else{
closest_end_here=A[i]+closest_end_here-0;
lend=i;
}
if(abs(closest_end_here-0)<abs(closest_so_far-0)){
closest_so_far=closest_end_here;
start=lstart;
end=lend;
}
}
for(int i=start;i<=end;i++)
cout<<A[i]<<" ";
cout<<endl;
cout<<closest_so_far<<endl;
}
return 0;
}
Here is a code implementation by java:
public class Solution {
/**
* #param nums: A list of integers
* #return: A list of integers includes the index of the first number
* and the index of the last number
*/
public ArrayList<Integer> subarraySumClosest(int[] nums) {
// write your code here
int len = nums.length;
ArrayList<Integer> result = new ArrayList<Integer>();
int[] sum = new int[len];
HashMap<Integer,Integer> mapHelper = new HashMap<Integer,Integer>();
int min = Integer.MAX_VALUE;
int curr1 = 0;
int curr2 = 0;
sum[0] = nums[0];
if(nums == null || len < 2){
result.add(0);
result.add(0);
return result;
}
for(int i = 1;i < len;i++){
sum[i] = sum[i-1] + nums[i];
}
for(int i = 0;i < len;i++){
if(mapHelper.containsKey(sum[i])){
result.add(mapHelper.get(sum[i])+1);
result.add(i);
return result;
}
else{
mapHelper.put(sum[i],i);
}
}
Arrays.sort(sum);
for(int i = 0;i < len-1;i++){
if(Math.abs(sum[i] - sum[i+1]) < min){
min = Math.abs(sum[i] - sum[i+1]);
curr1 = sum[i];
curr2 = sum[i+1];
}
}
if(mapHelper.get(curr1) < mapHelper.get(curr2)){
result.add(mapHelper.get(curr1)+1);
result.add(mapHelper.get(curr2));
}
else{
result.add(mapHelper.get(curr2)+1);
result.add(mapHelper.get(curr1));
}
return result;
}
}

find number that does not repeat in O(n) time O(1) space

for starters, I did have a look at these questions:
Given an array of integers where some numbers repeat 1 time, some numbers repeat 2 times and only one number repeats 3 times, how do you find the number that repeat 3 times
Algorithm to find two repeated numbers in an array, without sorting
this one different:
given an unsorted array of integers with one unique number and the rest numbers repeat 3 times,
i.e.:
{4,5,3, 5,3,4, 1, 4,3,5 }
we need to find this unique number in O(n) time and O(1) space
NOTE: this is not a homework, just I an nice question I came across
What about this one:
Idea: do bitwise addition mod 3
#include <stdio.h>
int main() {
int a[] = { 1, 9, 9, 556, 556, 9, 556, 87878, 87878, 87878 };
int n = sizeof(a) / sizeof(int);
int low = 0, up = 0;
for(int i = 0; i < n; i++) {
int x = ~(up & a[i]);
up &= x;
x &= a[i];
up |= (x & low);
low ^= x;
}
printf("single no: %d\n", low);
}
This solution works for all inputs.
The idea is to extract the bits of an integer from array and add to respective 32bit
bitmap 'b' (implemented as 32byte array to represent 32bit no.)
unsigned int a[7] = {5,5,4,10,4,9,9};
unsigned int b[32] = {0}; //Start with zeros for a 32bit no.
main1() {
int i, j;
unsigned int bit, sum =0 ;
for (i=0;i<7; i++) {
for (j=0; j<32; j++) { //This loop can be optimized!!!!
bit = ((a[i] & (0x01<<j))>>j); //extract the bit and move to right place
b[j] += bit; //add to the bitmap array
}
}
for (j=0; j<32; j++) {
b[j] %= 2; //No. repeating exactly 2 times.
if (b[j] == 1) {
sum += (unsigned int) pow(2, j); //sum all the digits left as 1 to get no
//printf("no. is %d", sum);
}
}
printf("no. is %d", sum);
}

Resources