Related
The question is - how many three numbers exits (of the provided) that sum to zero?
I'm wondering, how to implement this brute force method (below) in ruby? The main aspect of this is : what is better to use in a place of for loop? times?
a - is array of integers, the data that's provided
int N = a.length;
int count = 0;
for(int i = 0; i<N; i++)
for(int j = i+1; j<N; j++)
for(int k = j+ 1; k<N; k++)
if (a[i] + a[j] + a[k] == 0 )
count++;
return count;
How about:
a.combination(3).count{|x,y,z| x+y+z==0}
But I don't get the connection with Rails here ;)
def two_sum(nums, target)
seen = Hash.new
result = []
nums.each_with_index do |e, i|
if seen.has_key?(target-e)
result << [seen[target-e], i]
else
seen[e] = i
end
end
return result
end
def three_sum(nums)
nums.sort!
seen = Hash.new
results = []
nums.each_with_index do |e, i|
if !seen.has_key?(e)
two_sum(nums[i + 1 .. -1], 0 - e).each do |pair|
results << [e] + pair.map{ |j| nums[j + i + 1] }
end
seen[e] = i
end
end
return results.count
end
Suppose I have the C code below
for(i = 0; i < 10; i++){
printf("Hello");
if(i == 5){
a[3] = a[2] * 2;
if(a[3] == b)
i = a[3]; //Skip to index = a[3]; depends on runtime value
}
}
How to convert to Ruby? I know we can skip one iteration using next, but I have to skip a few iterations depending on conditional value and I don't know how many iterations to skip before runtime?
Here is the code I am actually working on (as mentioned by Coreyward):
I am looking for "straight line" in the array that the values differs less than 0.1(less than 0.1 will considered as a "straight line"). The range has to be longer than 50 to be considered as a long "line". After I find the line range [a,b], i wanna skip the iterations to upper limit b so it would not start again from a+1, and it will start to find new "straight line" from b+1
for(i=0; i<arr.Length; i++){
if(arr[i] - arr[i + 50] < 0.1){
m = i; //m is the starting point
for(j=i; j<arr.Length; j++){ //this loop makes sure all values differs less than 0.1
if(arr[i] - arr[j] < 0.1){
n = j;
}else{
break;
}
}
if(n - m > 50){ //Found a line with range greater than 50, and store the starting point to line array
line[i] = m
}
i = n //Start new search from n
}
}
Your case isn't easily covered by typical ruby iterators, but ruby also has ordinary while loops which can completely cover c-for. the following is equivalent to your c for loop above.
i = 0;
while i < 10
puts "Hello"
if i == 5
a[3] = a[2] * 2
i = a[3] if a[3] == b
end
# in your code above, the for increment i++ will execute after assigning new i,
# though the comment "Skip to index = a[3]" indicates that may not be your intent
i += 1
end
Another way is using the enumerator class:
iter = (1..10).to_enum
while true
value = iter.next
puts "value is #{value.inspect}"
if value == 5
3.times {value = iter.next}
end
end
gives
value is 1
value is 2
value is 3
value is 4
value is 5
value is 9
value is 10
StopIteration: iteration reached at end
from (irb):15:in `next'
from (irb):15
from C:/Ruby19/bin/irb:12:in `<main>'
This question already has answers here:
Maximum sum sublist?
(13 answers)
Closed 8 years ago.
In an interview one of my friends was asked to find the subarray of an array with maximum sum, this my solution to the problem , how can I improve the solution make it more optimal , should i rather consider doing in a recursive fashion ?
def get_max_sum_subset(x):
max_subset_sum = 0
max_subset_i = 0
max_subset_j = 0
for i in range(0,len(x)+1):
for j in range(i+1,len(x)+1):
current_sum = sum(x[i:j])
if current_sum > max_subset_sum:
max_subset_sum = current_sum
max_subset_i = i
max_subset_j = j
return max_subset_sum,max_subset_i,max_subset_j
Your solution is O(n^2). The optimal solution is linear. It works so that you scan the array from left to right, taking note of the best sum and the current sum:
def get_max_sum_subset(x):
bestSoFar = 0
bestNow = 0
bestStartIndexSoFar = -1
bestStopIndexSoFar = -1
bestStartIndexNow = -1
for i in xrange(len(x)):
value = bestNow + x[i]
if value > 0:
if bestNow == 0:
bestStartIndexNow = i
bestNow = value
else:
bestNow = 0
if bestNow > bestSoFar:
bestSoFar = bestNow
bestStopIndexSoFar = i
bestStartIndexSoFar = bestStartIndexNow
return bestSoFar, bestStartIndexSoFar, bestStopIndexSoFar
This problem was also discussed thourougly in Programming Pearls: Algorithm Design Techniques (highly recommended). There you can also find a recursive solution, which is not optimal (O(n log n)), but better than O(n^2).
This is a well-known problem that displays overlapping optimal substructure, which suggests a dynamic programming (DP) solution. Although DP solutions are usually quite tricky (I think so at least!), this one is a great example to get introduced to the whole concept.
The first thing to note is that the maximal subarray (which must be a contiguous portion of the given array A) ending at position j either consists of the maximimal subarray ending at position j-1 plus A[j], or is empty (this only occurs if A[j] < 0). In other words, we are asking whether the element A[j] is contributing positively to the current maximum sum ending at position j-1. If yes, include it in the maximal subarray so far; if not, don't. Thus, from solving smaller subproblems that overlap we can build up an optimal solution.
The sum of the maximal subarray ending at position j can then be given recursively by the following relation:
sum[0] = max(0, A[0])
sum[j] = max(0, sum[j-1] + A[j])
We can build up these answers in a bottom-up fashion by scanning A from left to right. We update sum[j] as we consider A[j]. We can keep track of the overall maximum value and the location of the maximal subarray through this process as well. Here is a quick solution I wrote up in Ruby:
def max_subarray(a)
sum = [0]
max, head, tail = sum[0], -1, -1
cur_head = 0
(0...a.size).each do |j|
# base case included below since sum[-1] = sum[0]
sum[j] = [0, sum[j-1] + a[j]].max
cur_head = j if sum[j-1] == 0
if sum[j] > max
max, head, tail = sum[j], cur_head, j
end
end
return max, head, tail
end
Take a look at my gist if you'd like to test this for yourself.
This is clearly a linear O(N) algorithm since only one pass through the list is required. Hope this helps!
let n - elements count, a(i) - your array f(i) - maximum sum of subarray that ends at position i (minimum length is 1). Then:
f(0) = a(i);
f(i) = max(f(i-1), 0) + a(i); //f(i-1) when we continue subarray, or 0 - when start at i position
max(0, f(1), f(2), ... , f(n-1)) - the answer
A much better solution approach can be derived by thinking about what conditions must hold for a maximum-sum sub-array: the first item on either end that is not included (if any) must be negative and the last item on either end that is included must be non-negative. You don't need to consider any other end points for the sub-array except where these changes occur in the original data.
There is a short video from MIT that helps you understand this dynamic programming problem.
http://people.csail.mit.edu/bdean/6.046/dp/
Click on the first link under the 'problems' section and you will see it.
Here is a simple O(N) algorithm from http://en.wikipedia.org/wiki/Maximum_subarray_problem
int maxsofar=0;
int maxendinghere=0;
for i=[0 n] {
maxendinghere=max(maxendinghere+x[i],0);
maxsofar=max(maxsofar,maxendinghere);
}
Unless I'm missing something important, if they are positive integers the subset would include the whole array, if they're integers, it would include only positive integers. Is there another constraint there?
Java solution:
Does not work for an array with all negatives.
public static int[] maxsubarray(int[] array) {
//empty array check
if (array.length == 0){
return new int[]{};
}
int max = 0;
int maxsofar = 0;
//indices
int maxsofarstart = 0;
int maxsofarend = 0;
int maxstartindex = 0;
for (int i = 0; i < array.length; i++) {
if (array[i] > 0) {
if (max == 0) {
maxstartindex = i;
}
max = max + array[i];
if (max > maxsofar) {
maxsofar = max;
maxsofarstart = maxstartindex;
maxsofarend = i;
}
} else {
max = 0;
}
}
return Arrays.copyOfRange(array, maxsofarstart, maxsofarend + 1);
}
here is one of most well-expained, tested, working solution - http://rerun.me/blog/2012/08/30/maximum-continuous-subarray-problem-kandanes-algorithm/
package me.rerun;
public class Kadane {
public static void main(String[] args) {
int[] intArr={3, -1, -1, -1, -1, -1, 2, 0, 0, 0 };
//int[] intArr = {-1, 3, -5, 4, 6, -1, 2, -7, 13, -3};
//int[] intArr={-6,-2,-3,-4,-1,-5,-5};
findMaxSubArray(intArr);
}
public static void findMaxSubArray(int[] inputArray){
int maxStartIndex=0;
int maxEndIndex=0;
int maxSum = Integer.MIN_VALUE;
int cumulativeSum= 0;
int maxStartIndexUntilNow=0;
for (int currentIndex = 0; currentIndex < inputArray.length; currentIndex++) {
int eachArrayItem = inputArray[currentIndex];
cumulativeSum+=eachArrayItem;
if(cumulativeSum>maxSum){
maxSum = cumulativeSum;
maxStartIndex=maxStartIndexUntilNow;
maxEndIndex = currentIndex;
}
else if (cumulativeSum<0){
maxStartIndexUntilNow=currentIndex+1;
cumulativeSum=0;
}
}
System.out.println("Max sum : "+maxSum);
System.out.println("Max start index : "+maxStartIndex);
System.out.println("Max end index : "+maxEndIndex);
}
}
This is the correct Java Code which will handle scenarios including all negative numbers.
public static long[] leftToISumMaximize(int N, long[] D) {
long[] result = new long[N];
result[0] = D[0];
long currMax = D[0];
for (int i = 1; i < N; i++) {
currMax = Math.max(D[i], currMax + D[i]);
result[i] = Math.max(result[i - 1], currMax);
}
return result;
}
Not sure but Accepted Solution didn't for work me for all the scenarios (May be I misunderstood it)
So I did small modification, instead of
if(value > 0)
I changed it yo
if(value > bestNow)
.....(I wrote it in Scala)
And it is working for the all scenarios
def findMaxSubArray(list: List[Int]): (Int, Int, Int) = {
var (bestNow,bestSoFar) = (0, 0)
var ( startIndexNow, startIndexSoFar, endIndex) = (-1, -1, -1)
for (i <- 0 until list.length) {
var value = bestNow + list(i)
if (value > bestNow) {
if (bestNow == 0)
startIndexNow = i
bestNow = value
} else
bestNow = 0
if (bestNow > bestSoFar) {
bestSoFar = bestNow
startIndexSoFar = startIndexNow
endIndex = i
}
}
return (bestSoFar, startIndexSoFar, endIndex)
}
def main(args: Array[String]) {
println(findMaxSubArray(List(3, -1, 5, 3, -6, -9, 6, 1)).toString)
println(findMaxSubArray(List(3, -1, 5, 3, -6, -9, 6, 3)).toString)
println(findMaxSubArray(List(20, -1, 5, 3, -6, -9, 6)).toString)
}
Output.....
(max =8, start=2, end=3)
(max=9, start=6, end=7)
(max=20, start=0, end= 0)
I have made a function for a little more general problem:
Find maximum sum subarray (meaning its bounds and sum, not only the sum)
If two subarrays have equal sums then pick the shorter one
If two equally long subarrays have equal sums then pick the one that appears first.
Function is based on Kadane's algorithm and it runs in O(n) time. Basically, this is it:
function MaxSumSubarray(a, n, start out, len out)
-- a - Array
-- n - Length of the array
-- start - On output starting position of largest subarray
-- len - On output length of largest subarray
-- Returns sum of the largest subarray
begin
start = 0
len = 1
int sum = a[0]
curStart = 0
curLen = 1
curSum = a[0]
for i = 2 to n
begin
if a[i] >= curSum + a[i] then
begin
curStart = i
curLen = 1
curSum = a[i]
end
else
begin
curLen = curLen + 1
curSum = curSum + a[i]
end
if (curSum > sum) OR
(curSum = sum AND curLen < len) OR
(curSum = sum AND curLen = len AND curStart < start) then
begin
start = curStart
len = curLen
sum = curSum
end
end
return sum
end
I've uploaded the whole solution in C#, with analysis and examples, in this article: Maximum Sum Subarray
I am working my way through the book Introduction to Algorithms, 3rd edition. One of the first things explained is the insertion sort. On page 18 there is some pseudo code:
A = { 5, 2, 4, 6, 1, 3 };
INSERTION-SORT(A)
1 for j = 2 to A.length
2 key = A[j]
4 i = j - 1
5 while (i > 0 and A[i] > key)
6 A[i + 1] = A[i]
7 i = i - 1
8 A[i + 1] = key
It says that pseudo code is used so that it is easily translated to any kind of language (C, C++, Java, they don't mention, but I guess C# too). Since I program in C#, I translated it in LinqPad.
int[] a = { 5, 2, 4, 6, 1, 3 };
for (var j = 1; j < a.Length; j++)
{
var key = a[j];
var i = j - 1;
while(i > 0 && a[i] > key)
{
a[i + 1] = a[i];
i--;
}
a[i + 1] = key;
}
a.Dump();
You're probably going to ask, why does j start at 1, when it clearly says 2? In the book, the array has an index starting at 1. And yes, I now I probably should have updated all the [i - 1] and [i + i] as well.
Anyways, after I was done, I run the code and notice that it doesn't actually sort correctly. The output is { 5, 1, 2, 3, 4, 6 }. It was late and should have stopped, but I struggled on to make the code correct. I did everything, even taking the pseudo code as is from the book (starting at 2). Still not the correct output.
I contacted one of the professors of the book, and he send me the code for the insertion sort, in C:
void insertion_sort(int *A, int n) {
for (int j = 2; j <= n; j++) {
int key = A[j];
int i = j-1;
while (i > 0 && A[i] > key) {
A[i+1] = A[i];
i--;
}
A[i+1] = key;
}
}
Translated in C#:
int[] a = { 5, 2, 4, 6, 1, 3 };
for (var j = 2; j <= a.Length; j++)
{
var key = a[j];
var i = j - 1;
while(i > 0 && a[i] > key)
{
a[i + 1] = a[i];
i--;
}
a[i + 1] = key;
}
I get an array out of bounds. Okay then maybe:
int[] a = { 5, 2, 4, 6, 1, 3 };
for (var j = 2; j <= a.Length - 1; j++)
{
var key = a[j];
var i = j - 1;
while(i > 0 && a[i] > key)
{
a[i + 1] = a[i];
i--;
}
a[i + 1] = key;
}
Output: { 5, 1, 2, 3, 4, 6 }
I'm thinking, this can't be correct. The pseudo code says 2 to array.Length. Is that 2 < array.Length, or 2 <= array.Length? What is going on here?
I personally think it is because of the 0 > 0 predicate in the while loop. It actually falls short one time each time.
My explanation (from my email sent to the professor, to lazy to type it all over):
The reason why the loop still ends up with { 5, 1, 2, 3, 4, 6 } is because of the i > 0 predicate. Every time in the while loop you subtract 1 of i (i--). This will eventually lead to 0 > 0 which ends up false (only 0 == 0 will return true), but this is when the loop still needs to run one more time. It continuously falls one short. It should go do the while loop 1 more time to properly sort.
Another explanation:
When j starts with 2, key == 4, i == 1 and a[i] == 2. The while loop won't run in this case because 2 > 0 but 2 isn't greater than 4.
j == 3,
key == 6,
i == 2,
a[i] == 4
While loop won't run because 4 is not greater than 6
j == 4,
key == 1,
i == 3,
a[i] == 6
While loop runs this time:
a[i + 1] = a[i] -> a[4] = a[3] -> { 5, 2, 4, 6, 6, 3 }
i-- -> i == 2
Again while loop because 2 > 0 and 4 > 1
a[i + 1] = a[i] -> a[3] = a[2] -> { 5, 2, 4, 4, 6, 3 }
i-- -> i == 1
Again while loop because 1 > 0 and 2 > 1
a[i + 1] = a[i] -> a[2] = a[1] -> { 5, 2, 2, 4, 6, 3 }
i-- -> i == 0
And here is where it goes (in my opinion) wrong. i is now equal to zero, but the while loop should run one more time to get the 5 out of the zero-th position.
The professor assures me that he is correct, but I can't get the right output. Where is my thinking going wrong?
The array in the C code that got sent to me by the professor was actually starting with an index of 1. I did not know this and checking upon C arrays I saw that they all start with 0. Yes, then the C code doesn't produce the correct output. The professor explained this to me and the pieces now fall into its place.
I think the prof is using 1-based array notation, so with while (i > 0 && a[i] > key), you are missing the a[0] element in the loop. Change your initial code to this then it works:
for (var j = 1; j < a.Length; j++)
{
var key = a[j];
var i = j - 1;
while(i >= 0 && a[i] > key) <----------- Try this, or you'd miss the first number
{
a[i + 1] = a[i];
i--;
}
a[i + 1] = key;
}
Also, if you want to use the professor's code, just ignore the 0-th element there.
On a side note, who did you contact? Rivest? Corman? Next time I get confused I think I'll try to contact him too, since it seems this professor reply mails:)
You should not think about translating the pseudocode, but about
translating your understanding of the algorithm.
The array is completely unsorted at first. The algorithm works by
taking successive unsorted elements and inserting them into the
already sorted part. The starting "sorted part" is the first element,
which is trivially "sorted". So, the first element to insert is the
second. Which is the index of the second element? Your j has to
start from there.
Then, i has to go through each of the sorted elements' indices,
backwards, until it either finds the place to insert the current value
or runs out of elements. So, where does it have to start, and where
does it have to end? Take care that it actually looks at each element
is has to.
Off-by-one errors are notoriously difficult to spot (and mixing
notions of 1-based and 0-based arrays surely does not help), but don't
just fiddle around until it seems to work. Try to understand what the
code is actually doing.
I believe your argument about i>0 is correct, regardless of what the prof. says. In the pseudo-code, the loop is while i > 0 and the array indexing starts with 1. In C#, array indexing starts with 0, therefore you should have while i >= 0.
I experienced the same problem. Below is the code in C which implements the above pseudo-code correctly. I am not using pointers, like other solutions.
Indeed, the tricky part about this was that the pseudo code is using 1-based array notations unlike most programming languages!
#include <stdio.h>
int main(void)
{
int A[] = { 50, 20, 10, 40, 60, 30 };
int j, key, len, i;
len = (sizeof(A)) / (sizeof(A[0]));
for (j = 1; j < 6; j++) { <-- Change here
key = A[j];
// Insert key into the sorted sequence A[1 .. j - 1].
i = j - 1;
while (i >= 0 && A[i] > key) { <-- Change here
A[i + 1] = A[i];
i--;
}
A[i + 1] = key;
}
for (int z = 0; z < len; z++) {
printf("%d ", A[z]);
}
printf("\n");
}
I also came across your problem, and I found the solution to this. I coded the algorithm in java as below.
int a[] = {5,2,4,3,1};
int key;
int i;
for(int j = 0; j < 5; j++)
{
key = a[j];
i = j - 1;
while(i>=0 && a[i]>key)
{
a[i+1]= a[i];
i--;
}
a[i+1] = key;
for(int k=0; k<a.length;k++)
{
System.out.print(a[k]+" ");
}
}
Remember: A.length goes from 0 to n, so Length should be A.Length -1. I made this algorithm for my students in C++ in spanish, using that book. Is simple to translate in C#.
some translation so you can understand better
largo = length
actual = current
cadena = chain
void InsertionSort::Sort(char cadena[])
{
int largo = strlen(cadena) - 1;
char actual = '0';
int i = 0;
for (int j = 1; j <= largo; j++)
{
actual = cadena[j];
i = j - 1;
while(i >= 0 && cadena[i] > actual)
{
cadena[i + 1] = cadena[i];
i--;
}
cadena[i + 1] = actual;
}
}
This question already has answers here:
Maximum sum sublist?
(13 answers)
Closed 8 years ago.
Given an array of integers, how can you find two indices, i and j, such that the sum of the elements in the subarray starting and ending at the indices is maximized, in linear time?
Simple. Assume you're given the array a. First, you calculate the array s, where s[i] = a[0]+a[1]+...+a[i]. You can do it in linear time:
s[0]=a[0];
for (i=1;i<N;i++) s[i]=s[i-1]+a[i];
Now, the sum a[i]+a[i+1]+..+a[j] is equal to s[j]-s[i-1]. For a fixed j, to maximize the value of this difference, you should find a minimal s[i-1] in range of 0..(j-1).
Imagine a usual algorithm to find minimal value in the array.
min = x[0];
for (j=1; j<N; j++)
if (x[j] < min)
min = x[j];
You iterate and compare each array element to min... But on each iteration this min is the lowest value in array, where index range is of 0..j! And that's what we're looking for!
global_max = a[0];
max_i = max_j = 0;
local_min_index = 0;
for (j=1; j<N; j++){
// here local_min is the lowest value of s[i], where 0<=i<j
if (s[j] - s[local_min_index] > global_max) {
global_max = s[j] - s[local_min_index]
//update indices
max_i = local_min_index + 1;
max_j = j;
}
//update local_min_index for next iteration
if (s[j]<local_min){
local_min = s[j];
// update indices
local_min_index = j;
}
}
from my copy of programming pearls:
maxsofar = 0
maxendinghere = 0
for i = [0, n)
/* invariant: maxendinghere and maxsofar are accurate
are accurate for x[0..i-1] */
maxendinghere = max(maxendinghere + x[i], 0)
maxsofar = max(maxsofar, maxendinghere)
this python code returns the bounds of the sequence. in terms of the original question, i=bestlo, j=besthi-1.
#
# given a sequence X of signed integers,
# find a contiguous subsequence that has maximal sum.
# return the lo and hi indices that bound the subsequence.
# the subsequence is X[lo:hi] (exclusive of hi).
#
def max_subseq(X):
#
# initialize vars to establish invariants.
# 1: best subseq so far is [bestlo..besthi), and bestsum is its sum
# 2: cur subseq is [curlo..curhi), and cursum is its sum
#
bestlo,besthi,bestsum = 0,0,0
curlo,curhi,cursum = 0,0,0
for i in xrange(len(X)):
# extend current subseq and update vars
curhi = i+1
cursum += X[i]
if cursum <= 0:
#
# the current subseq went under water,
# so it can't be usefully extended.
# start fresh at next index.
#
curlo = curhi
cursum = 0
elif cursum > bestsum:
# adopt current subseq as the new best
bestlo,besthi,bestsum = curlo,curhi,cursum
return (bestlo,besthi)
and here are some doctest examples that this code passes.
r'''
doctest examples:
>>> print max_subseq([])
(0, 0)
>>> print max_subseq([10])
(0, 1)
>>> print max_subseq([-1])
(0, 0)
>>> print max_subseq(xrange(5))
(1, 5)
>>> print max_subseq([-1, 1, -1])
(1, 2)
>>> print max_subseq([-1, -1, 1, 1, -1, -1, 1, 2, -1])
(6, 8)
>>> print max_subseq([-2, 11, -4, 13, -5, -2])
(1, 4)
>>> print max_subseq([4, -3, 5, -2, -1, 2, 6,-4])
(0, 7)
'''
You actually need Kadane's algorithm modification that remembers lower and upper bounds for the sub-array, here's C++11 code:
#include <iostream>
#include <vector>
typedef std::pair<std::vector<int>::iterator, std::vector<int>::iterator> SubSeq;
SubSeq getMaxSubSeq(std::vector<int> &arr) {
SubSeq maxSequence{arr.begin(), arr.begin()};
auto tmpBegin = arr.begin();
int maxEndingHere = 0;
int maxSoFar = 0;
for(auto it = arr.begin(); it < arr.end(); ++it) {
int currentSum = maxEndingHere + *it;
if(currentSum > 0) {
if(maxEndingHere == 0) {
tmpBegin = it;
}
maxEndingHere = currentSum;
} else {
maxEndingHere = 0;
}
if(maxEndingHere > maxSoFar) {
maxSoFar = maxEndingHere;
maxSequence.first = tmpBegin;
maxSequence.second = it + 1;
}
}
return maxSequence;
}
int main()
{
std::vector<int> arr{-1, 2, 90, -50, 150, -300, 56, 12};
auto seq = getMaxSubSeq(arr);
while(seq.first != seq.second) {
std::cout << *(seq.first) << " ";
++(seq.first);
}
return 0;
}