Compare commits
	
		
			2 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 84dbcf81ee | |||
| 2656ded38f | 
							
								
								
									
										1
									
								
								.idea/.name
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								.idea/.name
									
									
									
										generated
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
			
		||||
buy-and-sell-n-times
 | 
			
		||||
							
								
								
									
										4
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										4
									
								
								.idea/misc.xml
									
									
									
										generated
									
									
									
								
							@@ -4,5 +4,5 @@
 | 
			
		||||
  <component name="JavaScriptSettings">
 | 
			
		||||
    <option name="languageLevel" value="ES6" />
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="false" project-jdk-name="11" project-jdk-type="JavaSDK" />
 | 
			
		||||
</project>
 | 
			
		||||
  <component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK" />
 | 
			
		||||
</project>
 | 
			
		||||
							
								
								
									
										5
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										5
									
								
								.idea/vcs.xml
									
									
									
										generated
									
									
									
								
							@@ -1,5 +1,10 @@
 | 
			
		||||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<project version="4">
 | 
			
		||||
  <component name="GitSharedSettings">
 | 
			
		||||
    <option name="FORCE_PUSH_PROHIBITED_PATTERNS">
 | 
			
		||||
      <list />
 | 
			
		||||
    </option>
 | 
			
		||||
  </component>
 | 
			
		||||
  <component name="VcsDirectoryMappings">
 | 
			
		||||
    <mapping directory="" vcs="Git" />
 | 
			
		||||
  </component>
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,9 @@ allprojects {
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    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-params:5.6.0'
 | 
			
		||||
        testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.6.0'
 | 
			
		||||
 
 | 
			
		||||
@@ -1,20 +1,62 @@
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.io.*;
 | 
			
		||||
import java.math.*;
 | 
			
		||||
import java.util.stream.IntStream;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Template code to help you parse the standard input 
 | 
			
		||||
 * according to the problem statement.
 | 
			
		||||
 **/
 | 
			
		||||
class Solution {
 | 
			
		||||
	
 | 
			
		||||
	public static void main( String[] args ) {
 | 
			
		||||
		Scanner in = new Scanner( System.in );
 | 
			
		||||
		// read values with in.next...() methods
 | 
			
		||||
		
 | 
			
		||||
		// code your solution here
 | 
			
		||||
		
 | 
			
		||||
		// Write result with System.out.println()
 | 
			
		||||
		System.out.println( "value" );
 | 
			
		||||
	}
 | 
			
		||||
    
 | 
			
		||||
    public static void main( String[] args ) {
 | 
			
		||||
        // read values with in.next...() methods
 | 
			
		||||
        var scanner   = new Scanner( System.in );
 | 
			
		||||
        var sellCount = scanner.nextInt();
 | 
			
		||||
        var prices = scanner.tokens()
 | 
			
		||||
                            .mapToInt( Integer::valueOf )
 | 
			
		||||
                            .toArray();
 | 
			
		||||
        
 | 
			
		||||
        // Write result with System.out.println()
 | 
			
		||||
        System.out.println( maxProfits( sellCount, prices ));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    // code your solution here
 | 
			
		||||
    // 0 - 1 | ... | x-sellCount - x  -->  0 - x-1 | ... | x-1 - x
 | 
			
		||||
    private static int maxProfits( int sellCount, int[] prices ) {
 | 
			
		||||
        return IntStream.range( 0, sellCount )
 | 
			
		||||
                        .parallel()
 | 
			
		||||
                        .map( sale -> {
 | 
			
		||||
                            // recursion end condition
 | 
			
		||||
                            if ( sellCount == 1 ) {
 | 
			
		||||
                                return maxProfit( prices );
 | 
			
		||||
                            }
 | 
			
		||||
                            else {
 | 
			
		||||
                                return IntStream.range( 2, prices.length )
 | 
			
		||||
                                                .parallel()
 | 
			
		||||
                                                .map( index -> {
 | 
			
		||||
                                                    var       firstRange = Arrays.copyOfRange( prices, 0, index );
 | 
			
		||||
                                                    final int max1       = maxProfit( firstRange );
 | 
			
		||||
                    
 | 
			
		||||
                                                    var secondRange = Arrays.copyOfRange( prices, index - 1,
 | 
			
		||||
                                                                                          prices.length
 | 
			
		||||
                                                                                        );
 | 
			
		||||
                                                    // reduce range sizes recursively
 | 
			
		||||
                                                    final int max2 = maxProfits( sellCount - 1, secondRange );
 | 
			
		||||
                    
 | 
			
		||||
                                                    return max1 + max2;
 | 
			
		||||
                                                })
 | 
			
		||||
                                                .max().orElse( 0 );
 | 
			
		||||
                            }
 | 
			
		||||
                        })
 | 
			
		||||
                        .max().orElse( 0 );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
    private static int maxProfit( int[] prices ) {
 | 
			
		||||
        return IntStream.range( 0, prices.length )
 | 
			
		||||
                        .map( index -> {
 | 
			
		||||
                            var range = Arrays.copyOfRange( prices, Math.min( index + 1, prices.length - 1 ),
 | 
			
		||||
                                                            prices.length
 | 
			
		||||
                                                          );
 | 
			
		||||
                            int max = IntStream.of( range ).max().orElse( 0 );
 | 
			
		||||
                            // difference between current price and future maximum
 | 
			
		||||
                            return max - prices[index];
 | 
			
		||||
                        })
 | 
			
		||||
                        .max().orElse( 0 );
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										51
									
								
								src/test/java/BenchmarkExtension.java
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								src/test/java/BenchmarkExtension.java
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
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,77 +1,23 @@
 | 
			
		||||
import java.io.*;
 | 
			
		||||
 | 
			
		||||
import org.junit.jupiter.api.AfterAll;
 | 
			
		||||
import org.junit.jupiter.api.BeforeAll;
 | 
			
		||||
import com.github.stefanbirkner.systemlambda.SystemLambda;
 | 
			
		||||
import org.apache.commons.lang3.StringUtils;
 | 
			
		||||
import org.junit.jupiter.api.extension.ExtendWith;
 | 
			
		||||
import org.junit.jupiter.params.ParameterizedTest;
 | 
			
		||||
import org.junit.jupiter.params.provider.CsvFileSource;
 | 
			
		||||
 | 
			
		||||
import static java.nio.charset.StandardCharsets.UTF_8;
 | 
			
		||||
import static org.junit.jupiter.api.Assertions.*;
 | 
			
		||||
 | 
			
		||||
@ExtendWith( BenchmarkExtension.class )
 | 
			
		||||
class SolutionTest {
 | 
			
		||||
	
 | 
			
		||||
	static long totalDuration;
 | 
			
		||||
	
 | 
			
		||||
	@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 );
 | 
			
		||||
	}
 | 
			
		||||
    
 | 
			
		||||
    @ParameterizedTest
 | 
			
		||||
    @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() ));
 | 
			
		||||
    }
 | 
			
		||||
    
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,15 @@
 | 
			
		||||
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,4 +1,3 @@
 | 
			
		||||
sellCount, prices, maxProfit
 | 
			
		||||
2, 12 11 13 9 12 8 14 13 15, 10
 | 
			
		||||
3, 12 11 13 9 12 8 14 13 15, 12
 | 
			
		||||
2, 310 315 275 295 260 270 290 230 255 250, 55
 | 
			
		||||
 
 | 
			
		||||
		
		
			
  | 
		Reference in New Issue
	
	Block a user