Compare commits
	
		
			1 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e271940ba9 | 
							
								
								
									
										1
									
								
								.idea/.name
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1
									
								
								.idea/.name
									
									
									
										generated
									
									
									
								
							@@ -1 +0,0 @@
 | 
				
			|||||||
buy-and-sell-n-times
 | 
					 | 
				
			||||||
							
								
								
									
										2
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							@@ -4,5 +4,5 @@
 | 
				
			|||||||
  <component name="JavaScriptSettings">
 | 
					  <component name="JavaScriptSettings">
 | 
				
			||||||
    <option name="languageLevel" value="ES6" />
 | 
					    <option name="languageLevel" value="ES6" />
 | 
				
			||||||
  </component>
 | 
					  </component>
 | 
				
			||||||
  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK" />
 | 
					  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="false" project-jdk-name="11" project-jdk-type="JavaSDK" />
 | 
				
			||||||
</project>
 | 
					</project>
 | 
				
			||||||
							
								
								
									
										5
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							@@ -1,10 +1,5 @@
 | 
				
			|||||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
					<?xml version="1.0" encoding="UTF-8"?>
 | 
				
			||||||
<project version="4">
 | 
					<project version="4">
 | 
				
			||||||
  <component name="GitSharedSettings">
 | 
					 | 
				
			||||||
    <option name="FORCE_PUSH_PROHIBITED_PATTERNS">
 | 
					 | 
				
			||||||
      <list />
 | 
					 | 
				
			||||||
    </option>
 | 
					 | 
				
			||||||
  </component>
 | 
					 | 
				
			||||||
  <component name="VcsDirectoryMappings">
 | 
					  <component name="VcsDirectoryMappings">
 | 
				
			||||||
    <mapping directory="" vcs="Git" />
 | 
					    <mapping directory="" vcs="Git" />
 | 
				
			||||||
  </component>
 | 
					  </component>
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -16,9 +16,6 @@ allprojects {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    dependencies {
 | 
					    dependencies {
 | 
				
			||||||
        implementation 'org.apache.commons:commons-lang3:3.10'
 | 
					 | 
				
			||||||
        implementation 'org.apache.commons:commons-collections4:4.4'
 | 
					 | 
				
			||||||
        implementation 'org.apache.commons:commons-math3:3.6.1'
 | 
					 | 
				
			||||||
        testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
 | 
					        testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.0'
 | 
				
			||||||
        testImplementation 'org.junit.jupiter:junit-jupiter-params:5.6.0'
 | 
					        testImplementation 'org.junit.jupiter:junit-jupiter-params:5.6.0'
 | 
				
			||||||
        testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.0'
 | 
					        testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.0'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -18,45 +18,39 @@ class Solution {
 | 
				
			|||||||
	// code your solution here
 | 
						// code your solution here
 | 
				
			||||||
	// 0 - 1 | ... | x-sellCount - x  -->  0 - x-1 | ... | x-1 - x
 | 
						// 0 - 1 | ... | x-sellCount - x  -->  0 - x-1 | ... | x-1 - x
 | 
				
			||||||
	private static int maxProfits( int sellCount, int[] prices ) {
 | 
						private static int maxProfits( int sellCount, int[] prices ) {
 | 
				
			||||||
        return IntStream.range( 0, sellCount )
 | 
							var maxProfit = 0;
 | 
				
			||||||
                        .parallel()
 | 
							for ( int sale = 0; sale < sellCount; sale++ ) {
 | 
				
			||||||
                        .map( sale -> {
 | 
								int max = 0;
 | 
				
			||||||
			// recursion end condition
 | 
								// recursion end condition
 | 
				
			||||||
			if ( sellCount == 1 ) {  
 | 
								if ( sellCount == 1 ) {  
 | 
				
			||||||
                                return maxProfit( prices );
 | 
									max = maxProfit( prices );
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
			else {
 | 
								else {
 | 
				
			||||||
                                return IntStream.range( 2, prices.length )
 | 
									for ( int index = 2; index < prices.length; index++ ) {
 | 
				
			||||||
                                                .parallel()
 | 
					 | 
				
			||||||
                                                .map( index -> {
 | 
					 | 
				
			||||||
					var firstRange = Arrays.copyOfRange( prices, 0, index );
 | 
										var firstRange = Arrays.copyOfRange( prices, 0, index );
 | 
				
			||||||
					final int max1 = maxProfit( firstRange );
 | 
										final int max1 = maxProfit( firstRange );
 | 
				
			||||||
					
 | 
										
 | 
				
			||||||
                                                    var secondRange = Arrays.copyOfRange( prices, index - 1,
 | 
										var secondRange = Arrays.copyOfRange( prices, index, prices.length );
 | 
				
			||||||
                                                                                          prices.length
 | 
					 | 
				
			||||||
                                                                                        );
 | 
					 | 
				
			||||||
					// reduce range sizes recursively
 | 
										// reduce range sizes recursively
 | 
				
			||||||
					final int max2 = maxProfits( sellCount - 1, secondRange );
 | 
										final int max2 = maxProfits( sellCount - 1, secondRange );
 | 
				
			||||||
					
 | 
										
 | 
				
			||||||
                                                    return max1 + max2;
 | 
										max = Math.max( max, max1 + max2 );
 | 
				
			||||||
                                                })
 | 
					 | 
				
			||||||
                                                .max().orElse( 0 );
 | 
					 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
                        })
 | 
								}
 | 
				
			||||||
                        .max().orElse( 0 );
 | 
								maxProfit = Math.max( maxProfit, max );
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							return maxProfit;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
	private static int maxProfit( int[] prices ) {
 | 
						private static int maxProfit( int[] prices ) {
 | 
				
			||||||
        return IntStream.range( 0, prices.length )
 | 
							var maxProfit = 0;
 | 
				
			||||||
                        .map( index -> {
 | 
							for ( int index = 0; index < prices.length; index++ ) {
 | 
				
			||||||
                            var range = Arrays.copyOfRange( prices, Math.min( index + 1, prices.length - 1 ),
 | 
								var range = Arrays.copyOfRange( prices, Math.min( index + 1, prices.length - 1 ), prices.length );
 | 
				
			||||||
                                                            prices.length
 | 
					 | 
				
			||||||
                                                          );
 | 
					 | 
				
			||||||
			int max = IntStream.of( range ).max().orElse( 0 );
 | 
								int max = IntStream.of( range ).max().orElse( 0 );
 | 
				
			||||||
			// difference between current price and future maximum
 | 
								// difference between current price and future maximum
 | 
				
			||||||
                            return max - prices[index];
 | 
								maxProfit = Math.max( maxProfit, max - prices[index] );
 | 
				
			||||||
                        })
 | 
							}
 | 
				
			||||||
                        .max().orElse( 0 );
 | 
							return maxProfit;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,51 +0,0 @@
 | 
				
			|||||||
import org.junit.jupiter.api.extension.AfterAllCallback;
 | 
					 | 
				
			||||||
import org.junit.jupiter.api.extension.AfterTestExecutionCallback;
 | 
					 | 
				
			||||||
import org.junit.jupiter.api.extension.BeforeAllCallback;
 | 
					 | 
				
			||||||
import org.junit.jupiter.api.extension.BeforeTestExecutionCallback;
 | 
					 | 
				
			||||||
import org.junit.jupiter.api.extension.ExtensionContext;
 | 
					 | 
				
			||||||
import org.junit.jupiter.api.extension.ExtensionContext.Namespace;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import java.util.logging.Logger;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
import static java.lang.System.currentTimeMillis;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Based on TimingExtension from JUnit 5 user guide, and BenchmarkExtension from Nicolai Parlog
 | 
					 | 
				
			||||||
 * https://github.com/CodeFX-org/demo-junit-5/blob/master/src/main/java/org/codefx/demo/junit5/BenchmarkExtension.java
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public class BenchmarkExtension implements BeforeAllCallback, BeforeTestExecutionCallback, AfterTestExecutionCallback, AfterAllCallback {
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    private static final Namespace NAMESPACE = Namespace.create( BenchmarkExtension.class );
 | 
					 | 
				
			||||||
    private static final Logger LOGGER = Logger.getLogger( BenchmarkExtension.class.getName() );
 | 
					 | 
				
			||||||
        
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void beforeAll( ExtensionContext context ) {
 | 
					 | 
				
			||||||
        context.getStore( NAMESPACE ).put( context.getRequiredTestClass(), currentTimeMillis() );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void afterAll( ExtensionContext context ) {
 | 
					 | 
				
			||||||
        long launchTime  = context.getStore( NAMESPACE ).get( context.getRequiredTestClass(), long.class );
 | 
					 | 
				
			||||||
        long elapsedTime = currentTimeMillis() - launchTime;
 | 
					 | 
				
			||||||
        report( "Test class", context, elapsedTime );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void beforeTestExecution( ExtensionContext context ) {
 | 
					 | 
				
			||||||
        context.getStore( NAMESPACE ).put( context.getRequiredTestMethod(), currentTimeMillis() );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    @Override
 | 
					 | 
				
			||||||
    public void afterTestExecution( ExtensionContext context ) {
 | 
					 | 
				
			||||||
        long launchTime  = context.getStore( NAMESPACE ).get( context.getRequiredTestMethod(), long.class );
 | 
					 | 
				
			||||||
        long elapsedTime = currentTimeMillis() - launchTime;
 | 
					 | 
				
			||||||
        report( "Test", context, elapsedTime );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    private static void report( String unit, ExtensionContext context, long elapsedTime ) {
 | 
					 | 
				
			||||||
        String message = String.format( "%s '%s' took %d ms.", unit, context.getDisplayName(), elapsedTime );
 | 
					 | 
				
			||||||
        context.publishReportEntry( "Benchmark", message );
 | 
					 | 
				
			||||||
        LOGGER.info( message );
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
@@ -1,23 +1,77 @@
 | 
				
			|||||||
import com.github.stefanbirkner.systemlambda.SystemLambda;
 | 
					import java.io.*;
 | 
				
			||||||
import org.apache.commons.lang3.StringUtils;
 | 
					
 | 
				
			||||||
import org.junit.jupiter.api.extension.ExtendWith;
 | 
					import org.junit.jupiter.api.AfterAll;
 | 
				
			||||||
 | 
					import org.junit.jupiter.api.BeforeAll;
 | 
				
			||||||
import org.junit.jupiter.params.ParameterizedTest;
 | 
					import org.junit.jupiter.params.ParameterizedTest;
 | 
				
			||||||
import org.junit.jupiter.params.provider.CsvFileSource;
 | 
					import org.junit.jupiter.params.provider.CsvFileSource;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					import static java.nio.charset.StandardCharsets.UTF_8;
 | 
				
			||||||
import static org.junit.jupiter.api.Assertions.*;
 | 
					import static org.junit.jupiter.api.Assertions.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ExtendWith( BenchmarkExtension.class )
 | 
					 | 
				
			||||||
class SolutionTest {
 | 
					class SolutionTest {
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
    @ParameterizedTest
 | 
						static long totalDuration;
 | 
				
			||||||
    @CsvFileSource( resources = "testdata.csv" )
 | 
					 | 
				
			||||||
    void main( final String sellCount, final String input, final String expected ) throws Exception {
 | 
					 | 
				
			||||||
        String output = SystemLambda.tapSystemOutNormalized( () -> 
 | 
					 | 
				
			||||||
            SystemLambda.withTextFromSystemIn( sellCount + " " + input )
 | 
					 | 
				
			||||||
                        .execute( () -> Solution.main( new String[0] ))
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
        assertEquals( expected, StringUtils.chomp( output.trim() ));
 | 
						@BeforeAll
 | 
				
			||||||
 | 
						static void beforeAll() {
 | 
				
			||||||
 | 
							totalDuration = 0;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	
 | 
						
 | 
				
			||||||
 | 
						@AfterAll
 | 
				
			||||||
 | 
						static void afterAll() {
 | 
				
			||||||
 | 
							System.out.println( String.format( "All solutions took %01d.%03d secs",  totalDuration / 1000,  totalDuration % 1000 ));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						@ParameterizedTest
 | 
				
			||||||
 | 
						@CsvFileSource( resources = "testdata.csv", numLinesToSkip = 1 )
 | 
				
			||||||
 | 
						void main( final String sellCount, final String input, final String expected ) throws IOException {
 | 
				
			||||||
 | 
							// keep original streams
 | 
				
			||||||
 | 
							InputStream oldIn = System.in;
 | 
				
			||||||
 | 
							PrintStream oldOut = System.out;
 | 
				
			||||||
 | 
							PrintStream oldErr = System.err;
 | 
				
			||||||
 | 
							ByteArrayOutputStream bos =  new ByteArrayOutputStream();
 | 
				
			||||||
 | 
							
 | 
				
			||||||
 | 
							try {
 | 
				
			||||||
 | 
								redirectStreams(
 | 
				
			||||||
 | 
										new ByteArrayInputStream( (sellCount + " " + input).getBytes( UTF_8 )),
 | 
				
			||||||
 | 
										new PrintStream( bos, true, UTF_8 ),
 | 
				
			||||||
 | 
										new PrintStream( new ByteArrayOutputStream(), true, UTF_8 )
 | 
				
			||||||
 | 
								);
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// start time tracking
 | 
				
			||||||
 | 
								long start = System.currentTimeMillis();
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								Solution.main( new String[0] );
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// stop time tracking
 | 
				
			||||||
 | 
								long duration = System.currentTimeMillis() - start;
 | 
				
			||||||
 | 
								totalDuration += duration;
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								// restore streams
 | 
				
			||||||
 | 
								redirectStreams( oldIn, oldOut, oldErr );
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								System.out.println( String.format( "Solution took %01d.%03d secs",  duration / 1000,  duration % 1000 ));
 | 
				
			||||||
 | 
								
 | 
				
			||||||
 | 
								try (BufferedReader chk = new BufferedReader( new InputStreamReader( new ByteArrayInputStream( bos.toByteArray() ), UTF_8 ))) {
 | 
				
			||||||
 | 
									String[] expectedLines = expected.split( "\\s*[|]\\s*" );
 | 
				
			||||||
 | 
									
 | 
				
			||||||
 | 
									int lineCount = 0;
 | 
				
			||||||
 | 
									String line;
 | 
				
			||||||
 | 
									for ( ; (line = chk.readLine()) != null; lineCount++ ) {
 | 
				
			||||||
 | 
										assertEquals( expectedLines[ lineCount ], line );
 | 
				
			||||||
 | 
									}
 | 
				
			||||||
 | 
									assertEquals( expectedLines.length, lineCount );
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							finally {
 | 
				
			||||||
 | 
								// restore streams
 | 
				
			||||||
 | 
								redirectStreams( oldIn, oldOut, oldErr );
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
						static void redirectStreams( final InputStream input, final PrintStream output, final PrintStream error ) {
 | 
				
			||||||
 | 
							System.setIn( input );
 | 
				
			||||||
 | 
							System.setOut( output );
 | 
				
			||||||
 | 
							System.setErr( error );
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,15 +0,0 @@
 | 
				
			|||||||
package com.github.stefanbirkner.systemlambda;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Code that should be executed by on of the methods of {@link SystemLambda}.
 | 
					 | 
				
			||||||
 * This code may throw an {@link Exception}. Therefore we cannot use
 | 
					 | 
				
			||||||
 * {@link Runnable}.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
public interface Statement {
 | 
					 | 
				
			||||||
    /**
 | 
					 | 
				
			||||||
     * Execute the statement.
 | 
					 | 
				
			||||||
     *
 | 
					 | 
				
			||||||
     * @throws Exception the statement may throw an arbitrary exception.
 | 
					 | 
				
			||||||
     */
 | 
					 | 
				
			||||||
    void execute() throws Exception;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,3 +1,4 @@
 | 
				
			|||||||
 | 
					sellCount, prices, maxProfit
 | 
				
			||||||
2, 12 11 13 9 12 8 14 13 15, 10
 | 
					2, 12 11 13 9 12 8 14 13 15, 10
 | 
				
			||||||
3, 12 11 13 9 12 8 14 13 15, 12
 | 
					3, 12 11 13 9 12 8 14 13 15, 12
 | 
				
			||||||
2, 310 315 275 295 260 270 290 230 255 250, 55
 | 
					2, 310 315 275 295 260 270 290 230 255 250, 55
 | 
				
			||||||
 
 | 
				
			|||||||
		
		
			
  | 
		Reference in New Issue
	
	Block a user