Looking at Leetcode #53 (Maximum Subarray, https://leetcode.com/problems/maximum-subarray/), I saw this solution in the comments and adapted my code to it. There is one part I don't understand though — can someone explain?
I am looking to solve it with the sliding window approach.
class Solution {
public:
int maxSubArray(vector<int>& nums) { // runtime O(n), space O(1)
int largestSum = nums[0];
int windowSum = 0;
// int windowStart = 0;
for (int windowEnd = 0; windowEnd < nums.size(); windowEnd++) {
windowSum += nums[windowEnd];
if (nums[windowEnd] > windowSum) { // if the value at this index is greater than the running sum up to and including this index, abandon the running sum and restart the sliding window from here.
windowSum = nums[windowEnd];
// windowStart = windowEnd; is essentially what we are doing
}
if (windowSum > largestSum) { // the window has at least 1 number
largestSum = windowSum;
}
}
return largestSum;
}
};
I'm confused as to why it works that we abandon the running sum if we come across a value that standing alone is greater than the running sum. Can someone explain why this approach works to me? Maybe with an example or two? Failing to see why this doesn't skip potential sliding windows.
The code is poorly written, in a way which obscures its operation. In the if-condition you’re asking about, the only way it could be true is if the sum were negative before the beginning of the loop iteration. That’s what it’s really restarting in response to: an overall unhelpful prefix.
Related
My professor assigned homework to write a function that takes in an array of integers and sorts all zeros to the end of the array while maintaining the current order of non-zero ints. The constraints are:
Cannot use the STL or other templated containers.
Must have two solutions: one that emphasizes speed and another that emphasizes clarity.
I wrote up this function attempting for speed:
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
void sortArray(int array[], int size)
{
int i = 0;
int j = 1;
int n = 0;
for (i = j; i < size;)
{
if (array[i] == 0)
{
n++;
i++;
}
else if (array[i] != 0 && j != i)
{
array[j++] = array[i++];
}
else
{
i++;
n++;
}
}
while (j < size)
{
array[j++] = 0;
}
}
int main()
{
//Example 1
int array[]{20, 0, 0, 3, 14, 0, 5, 11, 0, 0};
int size = sizeof(array) / sizeof(array[0]);
sortArray(array, size);
cout << "Result :\n";
for (int i = 0; i < size; i++)
{
cout << array[i] << " ";
}
cout << endl << "Press any key to exit...";
cin.get();
return 0;
}
It outputs correctly, but;
I don't know what the speed of it actually is, can anyone help me figure out how to calculate that?
I have no idea how to go about writing a function for "clarity"; any ideas?
I my experience, unless you have very complicated algorithm, speed and clarity come together:
void sortArray(int array[], int size)
{
int item;
int dst = 0;
int src = 0;
// collect all non-zero elements
while (src < size) {
if (item = array[src++]) {
array[dst++] = item;
}
}
// fill the rest with zeroes
while (dst < size) {
array[dst++] = 0;
}
}
Speed comes from a good algorithm. Clarity comes from formatting, naming variables and commenting.
Speed as in complexity?
Since you are, and need, to look at all the elements in the array — and as such have a single loop going through the indexes in the range [0, N)—where N denotes the size of the input—your solution is O(N).
Further reading:
Plain English explanation of big O
Determining big O Notation
Regarding clearity
In my honest opinion there shouldn't need to be two alternatives when implementing such functionality as you are presenting. If you rename your variables to more suitable (descriptive) names your current solution should be clear enough to count as both performant and clear.
Your current approach can be written in plain english in a very clear fashion:
pseudo-explanation
set write_index to 0
set number_of_zeroes to 0
For each element in array
If element is 0
increase number_of_zeros by one
otherwise
write element value to position denoted by write_index
increase write_index by one
write number_of_zeroes 0s at the end of array
Having stated the explanation above we can quickly see that sortArray is not a descriptive name for your function, a more suitable name would probably be partition_zeroes or similar.
Adding comments could improve readability, but you current focus should lie in renaming your variables to better express the intent of the code.
(I feel your question is almost off-topic; I am answering it from a Linux perspective; I recommend using Linux to learn C++ programming; you'll adapt my advices to your operating system if you are using something else....)
speed
Regarding speed, you should have two complementary approaches.
The first (somehow "theoretical") is to analyze (i.e. think on) your algorithm and give (with some proof) its asymptotic time complexity.
The second approach (only "practical", and often pragmatical) is to benchmark and profile your program. Don't forget to compile with optimizations enabled (e.g. using g++ -Wall -O2 with GCC). Have a benchmark which runs for more than half of a second (so processes a large amount of data, e.g. several million numbers) and repeat it several times (e.g. using time(1) command on Linux). You could also measure some time inside your program using e.g. <chrono> in C++11, or just clock(3) (if you read a large array from some file, or build a large array of pseudo-random numbers with <random> or with random(3) you certainly want to measure separately the time to read or fill the array with the time to move zeros out of it). See also time(7).
(You need to process a large amount of data - more than a million items, perhaps many millions of them - because computer are very fast; a typical "elementary" operation -a machine instruction- takes less than a nanosecond, and you have lot of uncertainty on a single run, see this)
clarity
Regarding clarity, it is a bit subjective, but you might try to make your code readable and concise. Adding a few good comments could also help.
Be careful about naming: sorting is not exactly what your program is doing (it is more moving zeros than sorting the array)...
I think this is the best - Of course you may wish to use doxygen or some other
// Shift the non-zeros to the front and put zero in the rest of the array
void moveNonZerosTofront(int *list, unsigned int length)
{
unsigned int from = 0, to = 0;
// This will move the non-zeros
for (; from < length; ++from) {
if (list[from] != 0) {
list[to] = list[from];
to++;
}
}
// So the rest of the array needs to be assigned zero (as we found those on the way)
for (; to < length; +=to) {
list[to] = 0;
}
}
I was trying to implement my own bubble sort algorithm without looking at any pseudo-code online, but now that I've successfully done it, mine code looks really different from the examples I see online. They all involve dealing with a swapped variable that is either true or false. My implementation does not include that at all, so did I NOT make a bubble sort?
Here is an example I see online:
for i = 1:n,
swapped = false
for j = n:i+1,
if a[j] < a[j-1],
swap a[j,j-1]
swapped = true
→ invariant: a[1..i] in final position
break if not swapped
end
Here is my implementation of it:
void BubbleSort(int* a, int size)
{
while (!arraySorted(a, size))
{
int i = 0;
while (i < (size-1))
{
if (a[i] < a[i+1])
{
i++;
}
else
{
int tmp = 0;
tmp = a[i+1];
a[i+1] = a[i];
a[i] = tmp;
i++;
}
}
}
}
It does the same job, but does it do it any differently?
As some people noted, your version without the flag works, but is needlessly slow.
However, if you take the original version and just throw away the flag (together with the break), it will still work. It's easy to see from the invariant that you conveniently posted.
The version without the break has roughly the same worst-case performance as with the break (worst case is for an array sorted in reverse order). It's better than the original one if you want an algorithm that is guaranteed to finish in a pre-defined time.
Wikipedia describes another idea for optimization of the bubble-sort, which includes throwing away the break.
I have a vector holding 10 items (all of the same class for simplicity call it 'a'). What I want to do is to check that 'A' isn't either a) hiding the walls or b) hiding another 'A'. I have a collisions function that does this.
The idea is simply to have this looping class go though and move 'A' to the next position, if that potion is causing a collision then it needs to give itself a new random position on the screen. Because the screen is small, there is a good chance that the element will be put onto of another one (or on top of the wall etc). The logic of the code works well in my head - but debugging the code the object just gets stuck in the loop, and stay in the same position. 'A' is supposed to move about the screen, but it stays still!
When I comment out the Do while loop, and move the 'MoveObject()' Function up the code works perfectly the 'A's are moving about the screen. It is just when I try and add the extra functionality to it is when it doesn't work.
void Board::Loop(void){
//Display the postion of that Element.
for (unsigned int i = 0; i <= 10; ++i){
do {
if (checkCollisions(i)==true){
moveObject(i);
}
else{
objects[i]->ResetPostion();
}
}
while (checkCollisions(i) == false);
objects[i]->SetPosition(objects[i]->getXDir(),objects[i]->getYDir());
}
}
The class below is the collision detection. This I will expand later.
bool Board::checkCollisions(int index){
char boundry = map[objects[index]->getXDir()][objects[index]->getYDir()];
//There has been no collisions - therefore don't change anything
if(boundry == SYMBOL_EMPTY){
return false;
}
else{
return true;
}
}
Any help would be much appreciated. I will buy you a virtual beer :-)
Thanks
Edit:
ResetPostion -> this will give the element A a random position on the screen
moveObject -> this will look at the direction of the object and adjust the x and Y cord's appropriately.
I guess you need: do { ...
... } while (checkCollisions(i));
Also, if you have 10 elements, then i = 0; i < 10; i++
And btw. don't write if (something == true), simply if (something) or if (!something)
for (unsigned int i = 0; i <= 10; ++i){
is wrong because that's a loop for eleven items, use
for (unsigned int i = 0; i < 10; ++i){
instead.
You don't define what 'doesn't work' means, so that's all the help I can give for now.
There seems to be a lot of confusion here over basic language structure and logic flow. Writing a few very simple test apps that exercise different language features will probably help you a lot. (So will a step-thru debugger, if you have one)
do/while() is a fairly advanced feature that some people spend whole careers never using, see: do...while vs while
I recommend getting a solid foundation with while and if/else before even using for. Your first look at do should be when you've just finished a while or for loop and realize you could save a mountain of duplicate initialization code if you just changed the order of execution a bit. (Personally I don't even use do for that any more, I just use an iterator with while(true)/break since it lets me pre and post code all within a single loop)
I think this simplifies what you're trying to accomplish:
void Board::Loop(void) {
//Display the postion of that Element.
for (unsigned int i = 0; i < 10; ++i) {
while(IsGoingToCollide(i)) //check is first, do while doesn't make sense
objects[i]->ResetPosition();
moveObject(i); //same as ->SetPosition(XDir, YDir)?
//either explain difference or remove one or the other
}
}
This function name seems ambiguous to me:
bool Board::checkCollisions(int index) {
I'd recommend changing it to:
// returns true if moving to next position (based on inertia) will
// cause overlap with any other object's or structure's current location
bool Board::IsGoingToCollide(int index) {
In contrast checkCollisions() could also mean:
// returns true if there is no overlap between this object's
// current location and any other object's or structure's current location
bool Board::DidntCollide(int index) {
Final note: Double check that ->ResetPosition() puts things inside the boundaries.
Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
Suppose we have an array of numbers say {1,2,3} and we want to equalize the numbers in the least number of turns possible; where the definition of a "turn" is as follows:
In a turn, you need to fix the value of one of the elements as is, and increment every other number by 1.
Considering the eg. already mentioned - A={1,2,3} , the goal is to equalize them.What I've already done is formulate the logic i.e The method to using a minimum number of turns is to choose the maximum number in each turn.
Iteration 1: Hold A[2]=3. Array at end of iteration => {2,3,3}
Iteration 2: Hold A[2]=3. Array at end of iteration => {3,4,3}
Iteration 3: Hold A[1]=4. Array at end of iteration => {4,4,4}
So,number of turns taken = 3
The code I've written is as follows:
#include<iostream>
#include<stdio.h>
int findMax(int *a,int n)
{
int i,max;
max=1;
for(i=2;i<=n;i++)
{
if(a[i]>a[max])
{
max=i;
}
}
return max;
}
int equality(int *a,int n)
{
int i;
for(i=1;i<n;i++)
{
if(a[i]!=a[i+1]) return 0;
}
return 1;
}
int main()
{
int a[100],i,count,t,posn_max,n,ip=0;
scanf("%d",&t);
while(ip<t)
{
count=0;
scanf("%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
while(equality(a,n)==0)
{
posn_max=findMax(a,n);
for(i=1;i<=n;i++)
{
if(i!=posn_max)
{
a[i]=a[i]+1;
}
}
count++;
}
printf("%d\n",count);
ip++;
}
return 0;
}
This gives me the correct answer I need alright. But I want to optimize it further.
My Time Limit is 1.0 s . But the judge site tells me my code takes 1.01s. Can anyone help me out?
As far as I can see, I've used scanf/printf statements as compared to cout/cin, in a bid to optimize the input/output part. But what else should I be doing better?
In your algorithm, you are increasing all numbers in the expect for the maximum.
If you do it the other way around, decreasing the maximum and leaving the rest of the numbers, the result should be the same (but with much less memory/array operations)!
To make it even faster, you can get rid of the memory oeprations completely (as suggested by Ivaylo Strandjev also): Find the minimum number and by the idea above (of decreasing numbers instead of increasing) you know how much decreases you require to decrease all numbers to this minimum number. So, after finding the minimum you need one loop to calculate the number of turns.
Take your example of {1,2,3}
The minimum is 1
Number of turns: (1-1)+(2-1)+(3-1) = 0 + 1 + 2 = 3
If you are really clever, it is possible to calculate the number of turns directly when inputting the numbers and keeping track of the current minimum number... Try it! ;)
You only care about the count not about the actual actions you need to perform. So instead of performing the moves one by one try to find a way to count the number of moves without performing them. The code you wrote will not pass in the time limit no matter how well you optimize it. The maximum element observation you've made will help you along the way.
Besides the other comments, if I get this right and your code is just a little bit too slow, here are two optimizations which should help you.
First, you can combine equality() and findMax() and only scan once through the array instead of your current worst case (twice).
Second, you can split the "increase" loop into two parts (below and above the max position). This will remove the effort to check the position in the loop.
1) Try unrolling the loops
2) Can you use SIMD instruction? That would really speed this code up
I would printf in a separate thread, since it's an I/O operation and is much slower than your calculations.
It also does not demand complicated management e.g Producer-Consumer queue, since you only pass the ordered numbers from 0 to last count.
Here's the pseudo-code:
volatile int m_count = 0;
volatile bool isExit = false;
void ParallelPrint()
{
int currCount = 0;
while (!isExit)
{
while (currCount < m_count)
{
currCount++;
printf("%d\n", currCount);
}
Sleep(0); // just content switch
}
}
Open the thread before the scanf("%d",&t); (I guess this initialization time is not counted), and close the thread by isExit = true; before the return from your Main().
I'm trying to answer this problem as an exercise:
here are set of coins of {50,25,10,5,1} cents in a box.Write a program to find the number of ways a 1 dollar can be created by grouping the coins.
My solution involves making a tree with each edge having one of the values above. Each node would then hold a sum of the coins. I could then populate this tree and look for leaves that add up to 100. So here is my code
class TrieNode
{
public:
TrieNode(TrieNode* Parent=NULL,int sum=0,TrieNode* FirstChild=NULL,int children=0, bool key =false )
:pParent(Parent),pChild(FirstChild),isKey(key),Sum(sum),NoChildren(children)
{
if(Sum==100)
isKey=true;
}
void SetChildren(int children)
{
pChild = new TrieNode[children]();
NoChildren=children;
}
~TrieNode(void);
//pointers
TrieNode* pParent;
TrieNode* pChild;
int NoChildren;
bool isKey;
int Sum;
};
void Populate(TrieNode* Root, int coins[],int size)
{
//Set children
Root->SetChildren(size);
//add children
for(int i=0;i<size;i++)
{
TrieNode* child = &Root->pChild[0];
int c = Root->Sum+coins[i];
if(c<=100)
{
child = new TrieNode(Root,c);
if(!child->isKey) //recursively populate if not a key
Populate(child,coins,size);
}
else
child = NULL;
}
}
int getNumKeys(TrieNode* Root)
{
int keys=0;
if(Root == NULL)
return 0;
//increment keys if this is a key
if(Root->isKey)
keys++;
for(int i=0; i<Root->NoChildren;i++)
{
keys+= getNumKeys(&Root->pChild[i]);
}
return keys;
}
int _tmain(int argc, _TCHAR* argv[])
{
TrieNode* RootNode = new TrieNode(NULL,0);
int coins[] = {50,25,10,5,1};
int size = 5;
Populate(RootNode,coins,size);
int combos = getNumKeys(RootNode);
printf("%i",combos);
return 0;
}
The problem is that the tree is so huge that after a few seconds the program crashes. I'm running this on a windows 7, quad core, with 8gb ram. A rough calculation tells me I should have enough memory.
Are my calculations incorrect?
Does the OS limit how much memory I have access to?
Can I fix it while still using this solution?
All feedback is appreciated. Thanks.
Edit1:
I have verified that the above approach is wrong. By trying to build a tree with a set of only 1 coin.
coins[] = {1};
I found that the algorithm still failed.
After reading the post from Lenik and from João Menighin
I came up with this solution that ties both Ideas together to make a recursive solution
which takes any sized array
//N is the total the coins have to amount to
int getComobs(int coins[], int size,int N)
{
//write base cases
//if array empty | coin value is zero or N is zero
if(size==0 || coins[0]==0 ||N==0)
return 0;
int thisCoin = coins[0];
int atMost = N / thisCoin ;
//if only 1 coin denomination
if(size==1)
{
//if all coins fit in N
if(N%thisCoin==0)
return 1;
else
return 0;
}
int combos =0;
//write recursion
for(int denomination =0; denomination<atMost;denomination++)
{
coins++;//reduce array ptr
combos+= getComobs(coins, size-1,N-denomination*thisCoin);
coins--;//increment array ptr
}
return combos;
}
Thanks for all the feedback
Tree solution is totally wrong for this problem. It's like catching 10e6 tigers and then let go all of them but one, just because you need a single tiger. Very time and memory consuming -- 99.999% of your nodes are useless and should be ignored in the first place.
Here's another approach:
notice your cannot make a dollar to contain more than two 50 cents
notice again your cannot make a dollar to contain more than four 25 cent coins
notice... (you get the idea?)
Then your solution is simple:
for( int fifty=0; fifty<3; fifty++) {
for( int quarters=0; quarters<5; quarters++) {
for( int dimes=0; dimes<11; dimes++) {
for( int nickels=0; nickels<21; nickels++) {
int sum = fifty * 50 + quarters * 25 + dimes * 10 + nickels * 5;
if( sum <= 100 ) counter++; // here's a combination!!
}
}
}
}
You may ask, why did not I do anything about single cent coins? The answer is simple, as soon as the sum is less than 100, the rest is filled with 1 cents.
ps. hope this solution is not too simple =)
Ok, this is not a full answer but might help you.
You can try perform (what i call) a sanity check.
Put a static counter in TrieNode for every node created, and see how large it grows. If you did some calculations you should be able to tell if it goes to some insane values.
The system can limit the memory available, however it would be really bizarre. Usually the user/admin can set such limits for some purposes. This happens often in dedicated multi-user systems. Other thing could be having a 32bit app in 64bit windows environment. Then mem limit would be 4GB, however this would also be really strange. Any I don't think being limited by the OS is an issue here.
On a side note. I hope you do realize that you kinda defeated all object oriented programming concept with this code :).
I need more time to analyze your code, but for now I can tell that this is a classic Dynamic Programming problem. You may find some interesting texts here:
http://www.algorithmist.com/index.php/Coin_Change
and here
http://www.ccs.neu.edu/home/jaa/CSG713.04F/Information/Handouts/dyn_prog.pdf
There is a much easier way to find a solution:
#include <iostream>
#include <cstring>
using namespace std;
int main() {
int w[101];
memset(w, 0, sizeof(w));
w[0] = 1;
int d[] = {1, 5, 10, 25, 50};
for (int i = 0 ; i != 5 ; i++) {
for (int k = d[i] ; k <= 100 ; k++) {
w[k] += w[k-d[i]];
}
}
cout << w[100] << endl;
return 0;
}
(link to ideone)
The idea is to incrementally build the number of ways to make change by adding coins in progressively larger denomination. Each iteration of the outer loop goes through the results that we already have, and for each amount that can be constructed using the newly added coin adds the number of ways the combination that is smaller by the value of the current coin can be constructed. For example, if the current coin is 5 and the current amount is 7, the algorithm looks up the number of ways that 2 can be constructed, and adds it to the number of ways that 7 can be constructed. If the current coin is 25 and the current amount is 73, the algorithm looks up the number of ways to construct 48 (73-25) to the previously found number of ways to construct 73. In the end, the number in w[100] represents the number of ways to make one dollar (292 ways).
I really do believe someone has to put the most efficient and simple possible implementation, it is an improvement on lenik's answer:
Memory: Constant
Running time: Considering 100 as n, then running time is about O(n (lg(n))) <-I am unsure
for(int fifty=0; fifty <= 100; fifty+=50)
for(int quarters=0; quarters <= (100 - fifty); quarters+=25)
for(int dimes=0; dimes <= (100 - fifty - quarters); dimes+=10)
counter += 1 + (100 - fifty - quarters - dimes)/5;
I think this can be solved in constant time, because any sequence sum can be represented with a linear formula.
Problem might be infinite recursion. You are not incrementing c any where and loop runs with c<=100
Edit 1: I am not sure if
int c = Root->Sum+coins[i];
is actually taking it beyond 100. Please verify that
Edit 2: I missed the Sum being initialized correctly and it was corrected in the comments below.
Edit 3: Method to debug -
One more thing that you can do to help is, Write a print function for this tree or rather print on each level as it progresses deeper in the existing code. Add a counter which terminates loop after say total 10 iterations. The prints would tell you if you are getting garbage values or your c is gradually increasing in a right direction.