search in array where elements differ by 1 - algorithm

Interview question: Given an array where any two consecutive elements differ in their values by 1
example:
vector<int> vec = { 1, 0, -1, -2, -3, -4,-3,-2,-1,0,1, 2, 1, 2, 3 };
index==>0, 1, 2, 3, 4, 5, 6, 7, 8,9,10,11,12,13,14
The aim is to search an element K in this array in less than O(n).
My attempt:
start from index 0 . we can skip some indexes. Since elements differ by 1 and we need to search for k , lets insect elements and see a range in between which element could be found.
index = 0
The max value I can predict will be at a[idx + k] and min value at a[idx -k] as at each value differ by 1 .. however, this does not lead to anywhere
EDIT:
Code tried for suggestion given in an answer
#include "stdafx.h"
#include "vector"
#include "iostream"
using namespace std;
int closeS(vector<int> & vec, int search , int& hopsTaken)
{
int idx = 0;
while (idx < vec.size() && vec[idx] != search)
{
idx += abs (search - vec[idx]);
++hopsTaken;
}
if (idx < vec.size())
{
cout << idx <<"\n";
return idx;
}
return -1;
}
int main()
{
int hopsTaken = 0;
vector<int> vec = { 1,0,-1,-2,-3,-4,-3,-2,-1,0,1,2,1,2,3 };
cout << closeS(vec, 3, hopsTaken); // , 0, vec.size() - 1)];
cout << " \n hopsTaken " << hopsTaken <<" in array size" << vec.size() <<" for k = " << 3 <<"\n";
int y;
cin >> y;
return 0;
}
Tried few items and it was always <= O(n/k)
Still searching for better as its still O(n)

Begin at the first index and jump by the difference to the searched Element:
Eg Search for 2: Begin at index 0
0, vec[0]=1, 2-1=1 => nextindex 0+1=1
1, vec[1]=0, 2-0=2 => 1+2=3
3, vec[3]=-2, 2--2=4 => 3+4=7
7, vec[7]=-2, 2--2=4 => 7+4=11
11, vec[11]=2
Eg Search for 3: Begin at index 0
0, vec[0]=1, 3-1=2 => 0+2=2
2, vec[2]=-1, 3--1=4 => 2+4=6
6, vec[6]=-3, 3--3=6 => 6+6=12
12, vec[12]=1, 3-1=2 => 12+2=14
14, vec[11]=3

Related

Minimum number of steps required to make all elements of sequence 0

Given a sequence of integers calculate the minimum number of operations required to make all numbers 0. An operation is of the following:
Increase or decrease all numbers from index i to index j by 1.
Example 1)
{1, 1, -1}
You can do:
Decrease indices 0 to 1
Increase indices 2 to 2
So the answer is 2 operations.
Example 2)
{3, -1, -1, 3}
Decrease indices 0 to 3
Decrease indices 0 to 3
Decrease indices 0 to 3
Increase indices 1 to 2
Increase indices 1 to 2
Increase indices 1 to 2
Increase indices 1 to 2
So answer is 7.
What would be an efficient algorithm to do this?
One issue is that there are many ways to get final result to 0, even with the minimum number of operations in all cases.
For example, with {1, 0, 1}, we an apply -1 on [0, 2] and +1 on [1, 1]
or we can apply -1 on [0, 0], and then -1on [2, 2].
In both cases, two operations are needed.
As only the minimum number of operations is needed, we can decide to split the operations on distinct intervals as soon as it seems not suboptimal.
Then, an iterative procedure is applied, by comparing the values between adjacent indices.
For example, if the signs are different, or if the new value is 0, we can decide to split the intervals.
#include <iostream>
#include <vector>
int count_operations (const std::vector<int> &A) {
int n = A.size();
if (n == 0) return 0;
int count = std::abs (A[0]);
for (int i = 1; i < n; ++i) {
if (A[i]*A[i-1] > 0) {
if(std::abs(A[i]) > std::abs(A[i-1])) {
count += std::abs(A[i]) - std::abs(A[i-1]);
}
} else {
count += std::abs(A[i]);
}
}
return count;
}
int main() {
std::vector<int> A = {1 , 1, -1};
auto ans = count_operations (A);
std::cout << ans << "\n";
A = {3, -1, -1, 3};
ans = count_operations (A);
std::cout << ans << "\n";
return 0;
}

Algorithms: distribute elements far away from each other

I have an array of sorted integers. Given an integer N i need to place N largest elements further away from each other so that they have maximum space between each other. The remaining elements should be placed between these big items. For example, array of 10 with N=3 would result in [0, 5, 8, 2, 6, 9, 3, 7, 10, 4].
public static void main(String[] args) {
int[] start = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
int[] end = new int[10];
int N = 4;
int step = Math.round(start.length / N );
int y = 0;
int count = 0;
for (int i = 0; i < step; i++) {
for (int j = i; j<start.length; j = j + step) {
//System.out.println(j + " " + i);
if (count < start.length && start[count] != 0) {
end[j] = start[count];
count++;
}
}
}
System.out.println(end.toString());
}
You have an array of K elements. You have N max numbers you need to distribute. Then:
Step := K/N (removing the remainder)
Take any number from N maximum and insert it at Step/2 position.
Take other maximum numbers and insert it after the previous inserted maximum number at Step distance.
Giving [1,2,3,4,5,6,7,8,9,10]. So K = 10, N = 3. Then Step = 3. So the first maximum is placed at 3/2 position
[1,10,2,3,4,5,6,7,8,9]
Then other 2 are put at 3 distance from each other:
[1,10,2,3,9,4,5,8,6,7]
The code:
std::vector<int> Distribute(std::vector<int> aSource, int aNumber)
{
auto step = aSource.size() / aNumber; // Note integer dividing.
for (int i = 0; i < aNumber; ++i)
{
auto place = aSource.end() - i * step - step / 2;
aSource.insert(place, aSource.front());
aSource.erase(aSource.begin());
}
return aSource;
}
int main()
{
std::vector<int> vec{10,9,8,7,6,5,4,3,2,1,0,-1,-2,-3,-4,-5,-6,-7,-8,-9,-10};
auto res = Distribute(vec, 4);
for (auto e : res)
{
std::cout << e << ", ";
}
std::cout << std::endl;
}
Output:
6, 5, 4, 7, 3, 2, 1, 0, 8, -1, -2, -3, -4, 9, -5, -6, -7, -8, 10, -9, -10,

How can you determine how to place coins on a clock?

Say you are given a set of coins such as 4 10¢, 4 5¢, and 4 1¢.
You are asked to place these coins on a 12-hour analog clock face, where the next coin you place must be placed at X hours after the previous coin, where X is the value of the previous coin.
So if you place a 1¢ on 12, the next coin you place goes at 1. If you place a 5¢ on 1, the next coin you place goes at 6. And so on.
How can you maximize the number of coins that can be placed on the clock before the next coin would have to be placed in a slot that is already taken?
This is a problem I came across which I have been unable to solve except via exhaustive search. If the inputs are made to be arbitrary, exhaustive search fails quickly-- say it's an arbitrary number of coins of arbitrary various known denominations, with an arbitrary number of hours on the clock. Then you can't do exhaustive search anymore, because it becomes factorial time and fails on basis of excessive computational time requirements.
As maraca mentioned probably there isn't a much better solution than backtracking without more restrictions. Maybe with a larger number of coins of given denominations space can be covered with 'patterns'. Like coins [5, 10, 10, 5, 10, 10, 5, x] cover first 8 places and next coin is placed in similar location as first one. So the process can be repeated if there are enough coins.
Number of possible coin combinations in this case is not large at all. It is 12! / (4! * 4! * 4!) = 34650. For sure number explodes with larger parameters. Here is simple python code that solves 3 times larger problem which has possible coin combinations 3*10^15.
max_positions = []
max_order = None
def add_coin(coins, position, coin_order, occupied_positions, num_hours):
global max_positions, max_order
if position in occupied_positions or not coins:
# Can't place on that position or there is nothing more to place
if len(occupied_positions) > len(max_positions):
max_positions = occupied_positions
max_order = coin_order
return not coins # if all is covered return true to stop search
#
for c, num_coins in coins: # Try each coin
# Copy coins to new list and remove one used
c_coins = [x for x in coins if x[0] != c]
if num_coins > 1:
c_coins.append((c, num_coins-1))
# Next iteration
if add_coin(c_coins,
(position + c) % num_hours,
coin_order + [c],
occupied_positions + [position],
num_hours):
return True
def solve_coins(coins, num_hours):
global max_positions, max_order
max_positions = []
max_order = None
add_coin(coins, 0, [], [], num_hours)
print len(max_positions), max_positions, max_order
solve_coins([(1, 4), (5, 4), (10, 4)], 12)
solve_coins([(1, 8), (5, 8), (10, 8)], 24)
solve_coins([(1, 12), (5, 12), (10, 12)], 36)
output:
12 [0, 1, 6, 4, 2, 3, 8, 9, 7, 5, 10, 11] [1, 5, 10, 10, 1, 5, 1, 10, 10, 5, 1, 5]
24 [0, 1, 6, 16, 17, 3, 4, 14, 19, 5, 15, 20, 21, 2, 7, 8, 13, 18, 23, 9, 10, 11, 12, 22] [1, 5, 10, 1, 10, 1, 10, 5, 10, 10, 5, 1, 5, 5, 1, 5, 5, 5, 10, 1, 1, 1, 10, 10]
36 [0, 1, 6, 16, 17, 22, 23, 28, 2, 12, 13, 18, 19, 29, 34, 3, 8, 9, 10, 11, 21, 31, 5, 15, 20, 30, 35, 4, 14, 24, 25, 26, 27, 32, 33, 7] [1, 5, 10, 1, 5, 1, 5, 10, 10, 1, 5, 1, 10, 5, 5, 5, 1, 1, 1, 10, 10, 10, 10, 5, 10, 5, 5, 10, 10, 1, 1, 1, 5, 1, 10, 5]
// Expressing the coins as a list of buckets with the same modulo allows
// you to efficiently find the next coin to test and you don't start to
// calculate with the first penny and then do the same again starting
// with the second penny (or a 13-coin on a 12-clock), it is basically the same.
// Additionally it allows to remove and insert items at the current position in O(1).
// Also reverting is much better than copying whole states on each recursive call.
private class Bucket {
public int number;
public LinkedList<Integer> numbers = new LinkedList<>();
public Bucket(int number, int hours) {
this.number = number % hours;
numbers.add(number);
}
}
private LinkedList<Bucket> coins; // not using interface List as you are supposed to
private LinkedList<Integer> best, current; // because of removeLast()
private boolean[] occupied;
private int hours, limit;
public List<Integer> findBest(int[] coins, int hours) {
this.hours = hours;
// create buckets of coins with the same modulo
Integer[] c = Arrays.stream(coins).boxed().toArray( Integer[]::new );
// sort descending because a lot of small coins in a row are more likely to create
// an impassable area on the next pass around the clock
Arrays.sort(c, new Comparator<Integer>(){
public int compare(Integer a, Integer b) {
return Integer.compare(b.intValue() % hours, a.intValue() % hours);
}
});
this.coins = new LinkedList<>();
Bucket b = new Bucket(c[0].intValue(), hours);
this.coins.add(b);
int mod = c[0].intValue() % hours, coinCount = 1;
for (int i = 1; i < c.length; i++) {
int m = c[i].intValue() % hours;
if (m == mod) { // same bucket
b.numbers.add(c[i]);
} else { // new bucket
b = new Bucket(c[i].intValue(), hours);
this.coins.add(b);
mod = m;
}
coinCount++;
if (mod == 0) // don't need more than one 0 value
break;
}
best = new LinkedList<>();
current = new LinkedList<>();
occupied = new boolean[hours];
limit = coinCount < hours ? coinCount : hours; // max coins that can be placed
findBest(0);
return best;
}
private void findBest(int pos) {
if (best.size() == limit) // already found optimal solution
return;
if (occupied[pos] || current.size() == limit) {
if (current.size() > best.size())
best = (LinkedList<Integer>)current.clone();
return;
}
occupied[pos] = true;
for (int i = 0; i < coins.size(); i++) {
Bucket b = coins.get(i);
current.add(b.numbers.removeLast());
boolean removed = false;
if (b.numbers.size() == 0) { // bucket empty
coins.remove(i);
removed = true;
}
findBest((pos + b.number) % hours);
if (removed)
coins.add(i, b);
b.numbers.add(current.removeLast());
}
occupied[pos] = false;
}
Output for the given example: 10 10 5 1 1 1 5 10 10 1 5 5
Here is a slightly more optimized version in JavaScript where the list is implemented manually, so that you can really see why removing and adding the currend bucket is O(1). Because the list is always read in order it is superior to the array in this case. Whith an array you need to shift many elements or skip a lot of empty ones, depending how you implement it, not with a list of buckets. Should be a little easier to understand than the Java code.
var head, occupied, current, best, h, limit;
document.body.innerHTML = solve([1,1,1,1,5,5,5,5,10,10,10,10], 12);
function solve(coins, hours) {
h = hours;
coins.sort(function(a, b) {
let x = a % hours, y = b % hours;
if (x > y)
return -1;
if (x < y)
return 1;
return 0;
});
let mod = coins[0] % hours;
head = {num: mod, vals: [coins[0]], next: null};
let b = head, coinCount = 1;
for (let i = 1; i < coins.length && mod != 0; i++) {
let m = coins[i] % hours;
if (m == mod) {
b.vals.push(coins[i]);
} else {
b.next = {num: m, vals: [coins[i]], next: null};
b = b.next;
mod = m;
}
coinCount++;
}
limit = coinCount < hours ? coinCount : hours;
occupied = [];
for (let i = 0; i < hours; i++)
occupied.push(false);
best = [];
current = [];
solveRec(0);
return JSON.stringify(best);
}
function solveRec(pos) {
occupied[pos] = true;
let b = head, prev = null;
while (b !== null) {
let m = (pos + b.num) % h;
if (!occupied[m]) {
current.push(b.vals.pop());
let rem = false;
if (b.vals.length == 0) {
if (prev == null)
head = b.next;
else
prev.next = b.next;
rem = true;
}
solveRec(m);
if (current.length > best.length)
best = current.slice();
if (best.length == limit)
return;
if (rem) {
if (prev == null)
head = b;
else
prev.next = b;
}
b.vals.push(current.pop());
} else if (current.length + 1 > best.length) {
best = current.slice();
best.push(b.vals[b.vals.length - 1]);
}
prev = b;
b = b.next;
}
occupied[pos] = false;
}
I am still working on this, but it is already much better than O(n!). I will try to fit a new O() on it soon.
The concept is pretty simple, basically you create the smallest combos of numbers and then link them together into longer and longer strings of numbers until the next step is not possible.
A key to this working is that you don't track the front or end of a list of numbers, only the sum (and the inner sums due to their being calculated at earlier steps). so long as that sum is never divisible by clock, it will remain a clean solution.
Each step attempts to "splice" the smaller combos into the next size bigger:
(1,3), (3,1) -> (1,3,1), (3,1,3)
Here is a brief example (simplified) of what the algo is doing:
clock: 4
coins: 4
coins: 1,2,3,3
*bold pass, others are skipped for 1 of 3 reasons (not enough in population to build combo, sum divisible by clock, (in actual algo) prevent duplicates: (1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)
triples: (1,2,1), (2,1,2), (2,3,2), (3,2,3), (1,2,3), (2,3,3), (3,2,1), (3,3,2)
final combos:(1,2,3,x), (3,2,1,x)
This code is runnable standalone in c++ (but placeCoins is the algo):
I assume you will appropriate the algo to your purposes, but for anyone who wishes to run this cpp file, it will request clock size, coin count, and then after putting in coin count it will accept the next coin count number of inputs followed by enter as the coin values. The output will show the best counts, all orders at that count, and also during the algo it will show you the number of currently processing steps (which is where you can estimate complexity/ number of combos checked to see how much faster this is than exhaustive of any kind)
#include <iostream>
#include <vector>
#include <algorithm>
#include <numeric>
#include <map>
using namespace std;
//min clock size 3
vector<vector<int>> placeCoins(int _clockSize, vector<int> _coins)
{
int totalCheckedCombos = 0;
vector<vector<int>> coinGroups;
vector<int> coinSet = _coins;
sort(coinSet.begin(), coinSet.end());
coinSet.erase(unique(coinSet.begin(), coinSet.end()), coinSet.end());
map<int, int> coinCounts;
for (int i = 0; i < coinSet.size(); i++)
{
coinCounts[coinSet.at(i)] = count(_coins.begin(), _coins.end(), coinSet.at(i));
}
cout << "pairs" << endl;
//generate fair pairs of coins
for (int i = 0; i < coinSet.size(); i++)
{
for (int ii = 0; ii < coinSet.size(); ii++)
{
if ((coinSet.at(i) + coinSet.at(ii)) % _clockSize != 0)
{
if (i == ii)
{
if (coinCounts[coinSet.at(i)] > 1)
{
coinGroups.push_back({ coinSet.at(i),coinSet.at(ii) });
}
}
else
{
coinGroups.push_back({ coinSet.at(i),coinSet.at(ii) });
}
}
}
}
cout << "combine" << endl;
//iteratively combine groups of coins
for (int comboSize = 3; comboSize < _clockSize; comboSize++)
{
totalCheckedCombos += coinGroups.size();
vector<vector<int>> nextSizeCombos;
for (int i = 0; i < coinGroups.size(); i++)
{
for (int ii = 0; ii < coinGroups.size(); ii++)
{
//check combo to match
bool match = true;
for (int a = 0; a < comboSize - 2; a++)
{
if (coinGroups.at(i).at(a+1) != coinGroups.at(ii).at(a))
{
match = false;
break;
}
}
//check sum
if (match)
{
vector<int> tempCombo = coinGroups.at(i);
int newVal = coinGroups.at(ii).at(coinGroups.at(ii).size()-1);
tempCombo.push_back(newVal);
if (coinCounts[newVal] >= count(tempCombo.begin(), tempCombo.end(), newVal))
{
if (accumulate(tempCombo.begin(), tempCombo.end(), 0) % _clockSize != 0)
{
nextSizeCombos.push_back(tempCombo);
}
}
}
}
}
if (nextSizeCombos.size() == 0)
{
//finished, no next size combos found
break;
}
else
{
cout << nextSizeCombos.size() << endl;
coinGroups = nextSizeCombos;
}
}
cout << "total combos checked: " << totalCheckedCombos << endl;
return coinGroups;
}
int main(int argc, char** argv) {
int clockSize;
int coinCount;
vector<int> coins = {};
cout << "enter clock size: " << endl;
cin >> clockSize;
cout << "count number: " << endl;
cin >> coinCount;
for (int i = 0; i < coinCount; i++)
{
int tempCoin;
cin >> tempCoin;
coins.push_back(tempCoin);
}
cout << "press enter to compute combos: " << endl;
cin.get();
cin.get();
vector<vector<int>> resultOrders = placeCoins(clockSize, coins);
for (int i = 0; i < resultOrders.size(); i++)
{
cout << resultOrders.at(0).size()+1 << endl;
for (int ii = 0; ii < resultOrders.at(i).size(); ii++)
{
cout << resultOrders.at(i).at(ii) << " , ";
}
cout <<"x"<< endl;
}
cin.get();
cin.get();
}
ps: although I debugged this to a stable state, it still could definitely use fine tuning and optimization, but that is variable to different languages, so I just got the algo to work and called it good enough. If you see something glaringly wrong or poor form, feel free to comment and i'll fix it (or edit it directly if you want).
Instead of a greedy approach, try the maximum result of choosing a coin vs. not choosing a coin.
def valueOfClock(capacity, coins, n, hour):
if (n == 0 or capacity == 0 or hour > 12):
return 0
# Choose next coin if value is greater than the capacity
if (coins[n-1] > capacity):
valueOfClock(capacity, coins, n-1, hours)
# Choose max value of either choosing the next coin or
# choosing the current coin
return max(valueOfClock(capacity, coins, n-1, hours),
valueOfClock(capacity-coins[n-1], coins, n-1, hours + coins[n-1]))

Find longest increasing sequence

You are given a sequence of numbers and you need to find a longest increasing subsequence from the given input(not necessary continuous).
I found the link to this(Longest increasing subsequence on Wikipedia) but need more explanation.
If anyone could help me understand the O(n log n) implementation, that will be really helpful. If you could explain the algo with an example, that will be really appreciated.
I saw the other posts as well and what I did not understand is:
L = 0
for i = 1, 2, ... n:
binary search for the largest positive j ≤ L such that X[M[j]] < X[i] (or set j = 0 if no such value exists)
above statement, from where to start binary search? how to initialize M[], X[]?
A simpler problem is to find the length of the longest increasing subsequence. You can focus on understanding that problem first. The only difference in the algorithm is that it doesn't use the P array.
x is the input of a sequence, so it can be initialized as:
x = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
m keeps track of the best subsequence of each length found so far. The best is the one with the smallest ending value (allowing a wider range of values to be added after it). The length and ending value is the only data needed to be stored for each subsequence.
Each element of m represents a subsequence. For m[j],
j is the length of the subsequence.
m[j] is the index (in x) of the last element of the subsequence.
so, x[m[j]] is the value of the last element of the subsequence.
L is the length of the longest subsequence found so far. The first L values of m are valid, the rest are uninitialized. m can start with the first element being 0, the rest uninitialized. L increases as the algorithm runs, and so does the number of initialized values of m.
Here's an example run. x[i], and m at the end of each iteration is given (but values of the sequence are used instead of indexes).
The search in each iteration is looking for where to place x[i]. It should be as far to the right as possible (to get the longest sequence), and be greater than the value to its left (so it's an increasing sequence).
0: m = [0, 0] - ([0] is a subsequence of length 1.)
8: m = [0, 0, 8] - (8 can be added after [0] to get a sequence of length 2.)
4: m = [0, 0, 4] - (4 is better than 8. This can be added after [0] instead.)
12: m = [0, 0, 4, 12] - (12 can be added after [...4])
2: m = [0, 0, 2, 12] - (2 can be added after [0] instead of 4.)
10: m = [0, 0, 2, 10]
6: m = [0, 0, 2, 6]
14: m = [0, 0, 2, 6, 14]
1: m = [0, 0, 1, 6, 14]
9: m = [0, 0, 1, 6, 9]
5: m = [0, 0, 1, 5, 9]
13: m = [0, 0, 1, 5, 9, 13]
3: m = [0, 0, 1, 3, 9, 13]
11: m = [0, 0, 1, 3, 9, 11]
7: m = [0, 0, 1, 3, 7, 11]
15: m = [0, 0, 1, 3, 7, 11, 15]
Now we know there is a subsequence of length 6, ending in 15. The actual values in the subsequence can be found by storing them in the P array during the loop.
Retrieving the best sub-sequence:
P stores the previous element in the longest subsequence (as an index of x), for each number, and is updated as the algorithm advances. For example, when we process 8, we know it comes after 0, so store the fact that 8 is after 0 in P. You can work backwards from the last number like a linked-list to get the whole sequence.
So for each number we know the number that came before it. To find the subsequence ending in 7, we look at P and see that:
7 is after 3
3 is after 1
1 is after 0
So we have the subsequence [0, 1, 3, 7].
The subsequences ending in 7 or 15 share some numbers:
15 is after 11
11 is after 9
9 is after 6
6 is after 2
2 is after 0
So we have the subsequences [0, 2, 6, 9, 11], and [0, 2, 6, 9, 11, 15] (the longest increasing subsequence)
One of the best explanation to this problem is given by MIT site.
http://people.csail.mit.edu/bdean/6.046/dp/
I hope it will clear all your doubts.
based on FJB's answer, java implementation:
public class Lis {
private static int[] findLis(int[] arr) {
int[] is = new int[arr.length];
int index = 0;
is[0] = index;
for (int i = 1; i < arr.length; i++) {
if (arr[i] < arr[is[index]]) {
for (int j = 0; j <= index; j++) {
if (arr[i] < arr[is[j]]) {
is[j] = i;
break;
}
}
} else if (arr[i] == arr[is[index]]) {
} else {
is[++index] = i;
}
}
int[] lis = new int[index + 1];
lis[index] = arr[is[index]];
for (int i = index - 1; i >= 0; i--) {
if (is[i] < is[i + 1]) {
lis[i] = arr[is[i]];
} else {
for (int j = is[i + 1] - 1; j >= 0; j--) {
if (arr[j] > arr[is[i]] && arr[j] < arr[is[i + 1]]) {
lis[i] = arr[j];
is[i] = j;
break;
}
}
}
}
return lis;
}
public static void main(String[] args) {
int[] arr = new int[] { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11,
7, 15 };
for (int i : findLis(arr)) {
System.out.print(i + "-");
}
System.out.println();
arr = new int[] { 1, 9, 3, 8, 11, 4, 5, 6, 4, 19, 7, 1, 7 };
for (int i : findLis(arr)) {
System.out.print(i + "-");
}
System.out.println();
}
}
Below is the O(NLogN) longest increasing subsequence implementation:
// search for the index which can be replaced by the X. as the index can't be
//0 or end (because if 0 then replace in the findLIS() and if it's greater than the
//current maximum the just append)of the array "result" so most of the boundary
//conditions are not required.
public static int search(int[] result, int p, int r, int x)
{
if(p > r) return -1;
int q = (p+r)/2;
if(result[q] < x && result[q+1]>x)
{
return q+1;
}
else if(result[q] > x)
{
return search(result, p, q, x);
}
else
{
return search(result, q+1, r, x);
}
}
public static int findLIS(int[] a)
{
int[] result = new int[a.length];
result[0] = a[0];
int index = 0;
for(int i=1; i<a.length; i++)
{
int no = a[i];
if(no < result[0]) // replacing the min number
{
result[0] = no;
}
else if(no > result[index])//if the number is bigger then the current big then append
{
result[++index] = no;
}
else
{
int c = search(result, 0, index, no);
result[c] = no;
}
}
return index+1;
}
Late to the party, but here's a JavaScript implementation to go along with the others.. :)
var findLongestSubsequence = function(array) {
var longestPartialSubsequences = [];
var longestSubsequenceOverAll = [];
for (var i = 0; i < array.length; i++) {
var valueAtI = array[i];
var subsequenceEndingAtI = [];
for (var j = 0; j < i; j++) {
var subsequenceEndingAtJ = longestPartialSubsequences[j];
var valueAtJ = array[j];
if (valueAtJ < valueAtI && subsequenceEndingAtJ.length > subsequenceEndingAtI.length) {
subsequenceEndingAtI = subsequenceEndingAtJ;
}
}
longestPartialSubsequences[i] = subsequenceEndingAtI.concat();
longestPartialSubsequences[i].push(valueAtI);
if (longestPartialSubsequences[i].length > longestSubsequenceOverAll.length) {
longestSubsequenceOverAll = longestPartialSubsequences[i];
}
}
return longestSubsequenceOverAll;
};
Based on #fgb 's answer, I implemented the algorithm using c++ to find the longest strictly increasing sub-sequence. Hope this will be somewhat helpful.
M[i] is the index of the last element of the sequence whose length is i, P[i] is the index of the previous element of i in the sequence, which is used to print the whole sequence.
main() is used to run the simple test case: {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}.
#include <vector>
using std::vector;
int LIS(const vector<int> &v) {
int size = v.size(), max_len = 1;
// M[i] is the index of the last element of the sequence whose length is i
int *M = new int[size];
// P[i] is the index of the previous element of i in the sequence, which is used to print the whole sequence
int *P = new int[size];
M[0] = 0; P[0] = -1;
for (int i = 1; i < size; ++i) {
if (v[i] > v[M[max_len - 1]]) {
M[max_len] = i;
P[i] = M[max_len - 1];
++max_len;
continue;
}
// Find the position to insert i using binary search
int lo = 0, hi = max_len - 1;
while (lo <= hi) {
int mid = lo + ((hi - lo) >> 1);
if (v[i] < v[M[mid]]) {
hi = mid - 1;
} else if (v[i] > v[M[mid]]) {
lo = mid + 1;
} else {
lo = mid;
break;
}
}
P[i] = P[M[lo]]; // Modify the previous pointer
M[lo] = i;
}
// Print the whole subsequence
int i = M[max_len - 1];
while (i >= 0) {
printf("%d ", v[i]);
i = P[i];
}
printf("\n");
delete[] M, delete[] P;
return max_len;
}
int main(int argc, char* argv[]) {
int data[] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15};
vector<int> v;
v.insert(v.end(), data, data + sizeof(data) / sizeof(int));
LIS(v);
return 0;
}
The O(N lg N) solution comes from patience sorting of playing card. I found this from my code comment and hence sharing here. I believe it would be really easier to understand for everyone how it works. Also you can find all possible longest increasing sub-sequence list if you understand well.
https://www.cs.princeton.edu/courses/archive/spring13/cos423/lectures/LongestIncreasingSubsequence.pdf
Code:
vector<int> lisNlgN(vector<int> v) {
int n = v.size();
vector<int> piles = vector<int>(n, INT_MAX);
int maxLen = 0;
for(int i = 0; i < n; i++) {
int pos = lower_bound(piles.begin(), piles.end(), v[i]) - piles.begin();
piles[pos] = v[i];
maxLen = max(maxLen, pos+1); // Plus 1 because of 0-based index.
}
// // Print piles for debug purpose
// for (auto x : piles) cout << x << " ";
// cout << endl;
//
// // Print position for debug purpose
// for (auto x : position) cout << x << " ";
// cout << endl;
vector<int> ret = vector<int>(piles.begin(), piles.begin() + maxLen);
return ret;
}
Code:
vector<vector<int>> allPossibleLIS(vector<int> v) {
struct Card {
int val;
Card* parent = NULL;
Card(int val) {
this->val = val;
}
};
auto comp = [](Card* a, Card* b) {
return a->val < b->val;
};
int n = v.size();
// Convert integers into card node
vector<Card*> cards = vector<Card*>(n);
for (int i = 0; i < n; i++) cards[i] = new Card(v[i]);
vector<Card*> piles = vector<Card*>(n, new Card(INT_MAX));
vector<Card*> lastPileCards;
int maxLen = 0;
for(int i = 0; i < n; i++) {
int pos = lower_bound(piles.begin(), piles.end(), new Card(v[i]), comp) - piles.begin();
piles[pos] = cards[i];
// Link to top card of left pile
if (pos == 0) cards[i]->parent = NULL;
else cards[i]->parent = piles[pos-1];
// Plus 1 because of 0-based index.
if (pos+1 == maxLen) {
lastPileCards.push_back(cards[i]);
} else if (pos+1 > maxLen) {
lastPileCards.clear();
lastPileCards.push_back(cards[i]);
maxLen = pos + 1;
}
}
// Print for debug purpose
// printf("maxLen = %d\n", maxLen);
// printf("Total unique lis list = %d\n", lastPileCards.size());
vector<vector<int>> ret;
for (auto card : lastPileCards) {
vector<int> lis;
Card* c = card;
while (c != NULL) {
lis.push_back(c->val);
c = c->parent;
}
reverse(lis.begin(), lis.end());
ret.push_back(lis);
}
return ret;
}

find largest submatrix algorithm

I have an N*N matrix (N=2 to 10000) of numbers that may range from 0 to 1000.
How can I find the largest (rectangular) submatrix that consists of the same number?
Example:
1 2 3 4 5
-- -- -- -- --
1 | 10 9 9 9 80
2 | 5 9 9 9 10
3 | 85 86 54 45 45
4 | 15 21 5 1 0
5 | 5 6 88 11 10
The output should be the area of the submatrix, followed by 1-based coordinates of its top left element. For the example, it would be (6, 2, 1) because there are six 9s situated at column 2, row 1.
This is a work in progress
I thought about this problem and I think I may have a O(w*h) algorithm.
The idea goes like this:
for any (i,j) compute the highest number of cells with the same value in the column j starting from (i,j). Store this values as heights[i][j].
create an empty vector of sub matrix (a lifo)
for all row: i
for all column: j
pop all sub matrix whose height > heights[i][j]. Because the submatrix with height > heights[i][j] cannot continue on this cell
push a submatrix defined by (i,j,heights[i][j]) where j is the farest coordinate where we can fit a submatrix of height: heights[i][j]
update the current max sub matrix
The tricky part is in the inner loop. I use something similar to the max subwindow algorithm to ensure it is O(1) on average for each cell.
I will try to formulate a proof but in the meantime here is the code.
#include <algorithm>
#include <iterator>
#include <iostream>
#include <ostream>
#include <vector>
typedef std::vector<int> row_t;
typedef std::vector<row_t> matrix_t;
std::size_t height(matrix_t const& M) { return M.size(); }
std::size_t width (matrix_t const& M) { return M.size() ? M[0].size() : 0u; }
std::ostream& operator<<(std::ostream& out, matrix_t const& M) {
for(unsigned i=0; i<height(M); ++i) {
std::copy(begin(M[i]), end(M[i]),
std::ostream_iterator<int>(out, ", "));
out << std::endl;
}
return out;
}
struct sub_matrix_t {
int i, j, h, w;
sub_matrix_t(): i(0),j(0),h(0),w(1) {}
sub_matrix_t(int i_,int j_,int h_,int w_):i(i_),j(j_),h(h_),w(w_) {}
bool operator<(sub_matrix_t const& rhs) const { return (w*h)<(rhs.w*rhs.h); }
};
// Pop all sub_matrix from the vector keeping only those with an height
// inferior to the passed height.
// Compute the max sub matrix while removing sub matrix with height > h
void pop_sub_m(std::vector<sub_matrix_t>& subs,
int i, int j, int h, sub_matrix_t& max_m) {
sub_matrix_t sub_m(i, j, h, 1);
while(subs.size() && subs.back().h >= h) {
sub_m = subs.back();
subs.pop_back();
sub_m.w = j-sub_m.j;
max_m = std::max(max_m, sub_m);
}
// Now sub_m.{i,j} is updated to the farest coordinates where there is a
// submatrix with heights >= h
// If we don't cut the current height (because we changed value) update
// the current max submatrix
if(h > 0) {
sub_m.h = h;
sub_m.w = j-sub_m.j+1;
max_m = std::max(max_m, sub_m);
subs.push_back(sub_m);
}
}
void push_sub_m(std::vector<sub_matrix_t>& subs,
int i, int j, int h, sub_matrix_t& max_m) {
if(subs.empty() || subs.back().h < h)
subs.emplace_back(i, j, h, 1);
}
void solve(matrix_t const& M, sub_matrix_t& max_m) {
// Initialize answer suitable for an empty matrix
max_m = sub_matrix_t();
if(height(M) == 0 || width(M) == 0) return;
// 1) Compute the heights of columns of the same values
matrix_t heights(height(M), row_t(width(M), 1));
for(unsigned i=height(M)-1; i>0; --i)
for(unsigned j=0; j<width(M); ++j)
if(M[i-1][j]==M[i][j])
heights[i-1][j] = heights[i][j]+1;
// 2) Run through all columns heights to compute local sub matrices
std::vector<sub_matrix_t> subs;
for(int i=height(M)-1; i>=0; --i) {
push_sub_m(subs, i, 0, heights[i][0], max_m);
for(unsigned j=1; j<width(M); ++j) {
bool same_val = (M[i][j]==M[i][j-1]);
int pop_height = (same_val) ? heights[i][j] : 0;
int pop_j = (same_val) ? j : j-1;
pop_sub_m (subs, i, pop_j, pop_height, max_m);
push_sub_m(subs, i, j, heights[i][j], max_m);
}
pop_sub_m(subs, i, width(M)-1, 0, max_m);
}
}
matrix_t M1{
{10, 9, 9, 9, 80},
{ 5, 9, 9, 9, 10},
{85, 86, 54, 45, 45},
{15, 21, 5, 1, 0},
{ 5, 6, 88, 11, 10},
};
matrix_t M2{
{10, 19, 9, 29, 80},
{ 5, 9, 9, 9, 10},
{ 9, 9, 54, 45, 45},
{ 9, 9, 5, 1, 0},
{ 5, 6, 88, 11, 10},
};
int main() {
sub_matrix_t answer;
std::cout << M1 << std::endl;
solve(M1, answer);
std::cout << '(' << (answer.w*answer.h)
<< ',' << (answer.j+1) << ',' << (answer.i+1) << ')'
<< std::endl;
answer = sub_matrix_t();
std::cout << M2 << std::endl;
solve(M2, answer);
std::cout << '(' << (answer.w*answer.h)
<< ',' << (answer.j+1) << ',' << (answer.i+1) << ')'
<< std::endl;
}
This is an order Rows*Columns Solution
It works by
starting at the bottom of the array, and determining how many items below each number match it in a column. This is done in O(MN) time (very trivially)
Then it goes top to bottom & left to right and sees if any given number matches the number to the left. If so, it keeps track of how the heights relate to each other to track the possible rectangle shapes
Here is a working python implementation. Apologies since I'm not sure how to get the syntax highlighting working
# this program finds the largest area in an array where all the elements have the same value
# It solves in O(rows * columns) time using O(rows*columns) space using dynamic programming
def max_area_subarray(array):
rows = len(array)
if (rows == 0):
return [[]]
columns = len(array[0])
# initialize a blank new array
# this will hold max elements of the same value in a column
new_array = []
for i in range(0,rows-1):
new_array.append([0] * columns)
# start with the bottom row, these all of 1 element of the same type
# below them, including themselves
new_array.append([1] * columns)
# go from the second to bottom row up, finding how many contiguous
# elements of the same type there are
for i in range(rows-2,-1,-1):
for j in range(columns-1,-1,-1):
if ( array[i][j] == array[i+1][j]):
new_array[i][j] = new_array[i+1][j]+1
else:
new_array[i][j] = 1
# go left to right and match up the max areas
max_area = 0
top = 0
bottom = 0
left = 0
right = 0
for i in range(0,rows):
running_height =[[0,0,0]]
for j in range(0,columns):
matched = False
if (j > 0): # if this isn't the leftmost column
if (array[i][j] == array[i][j-1]):
# this matches the array to the left
# keep track of if this is a longer column, shorter column, or same as
# the one on the left
matched = True
while( new_array[i][j] < running_height[-1][0]):
# this is less than the one on the left, pop that running
# height from the list, and add it's columns to the smaller
# running height below it
if (running_height[-1][1] > max_area):
max_area = running_height[-1][1]
top = i
right = j-1
bottom = i + running_height[-1][0]-1
left = j - running_height[-1][2]
previous_column = running_height.pop()
num_columns = previous_column[2]
if (len(running_height) > 0):
running_height[-1][1] += running_height[-1][0] * (num_columns)
running_height[-1][2] += num_columns
else:
# for instance, if we have heights 2,2,1
# this will trigger on the 1 after we pop the 2 out, and save the current
# height of 1, the running area of 3, and running columsn of 3
running_height.append([new_array[i][j],new_array[i][j]*(num_columns),num_columns])
if (new_array[i][j] > running_height[-1][0]):
# longer then the one on the left
# append this height and area
running_height.append([new_array[i][j],new_array[i][j],1])
elif (new_array[i][j] == running_height[-1][0]):
# same as the one on the left, add this area to the one on the left
running_height[-1][1] += new_array[i][j]
running_height[-1][2] += 1
if (matched == False or j == columns -1):
while(running_height):
# unwind the maximums & see if this is the new max area
if (running_height[-1][1] > max_area):
max_area = running_height[-1][1]
top = i
right = j
bottom = i + running_height[-1][0]-1
left = j - running_height[-1][2]+1
# this wasn't a match, so move everything one bay to the left
if (matched== False):
right = right-1
left = left-1
previous_column = running_height.pop()
num_columns = previous_column[2]
if (len(running_height) > 0):
running_height[-1][1] += running_height[-1][0] * num_columns
running_height[-1][2] += num_columns
if (matched == False):
# this is either the left column, or we don't match to the column to the left, so reset
running_height = [[new_array[i][j],new_array[i][j],1]]
if (running_height[-1][1] > max_area):
max_area = running_height[-1][1]
top = i
right = j
bottom = i + running_height[-1][0]-1
left = j - running_height[-1][2]+1
max_array = []
for i in range(top,bottom+1):
max_array.append(array[i][left:right+1])
return max_array
numbers = [[6,4,1,9],[5,2,2,7],[2,2,2,1],[2,3,1,5]]
for row in numbers:
print row
print
print
max_array = max_area_subarray(numbers)
max_area = len(max_array) * len(max_array[0])
print 'max area is ',max_area
print
for row in max_array:
print row

Resources