This is an iPython Notebook!


In [1]:
# you can mix text and code in one place and
# run code from a Web browser

Basics

All you need to know about Python is here:

You don't need to specify type of a variable


In [2]:
a = 10

In [3]:
a


Out[3]:
10

You can assign several variables at once:


In [4]:
a, b = 1, 2
a, b


Out[4]:
(1, 2)

In [5]:
b, a = a, b
a, b


Out[5]:
(2, 1)

There is no "begin-end"! You use indentation to specify blocks. Here is simple IF statement:


In [6]:
if a > b:
    print("A is greater than B")
else:
    print("B is greater than A")


A is greater than B

Types


In [7]:
# Integer
a = 1
print(a)

# Float
b = 1.0
print(b)

# String
c = "Hello world"
print(c)

# Unicode
d = u"Привет, мир!"
print(d)

# List (array)
e = [1, 2, 3]
print(e[2]) # 3

# Tuple (constant array)
f = (1, 2, 3)
print(f[0]) # 1

# Set
g = {1, 1, 1, 2}
print(g)

# Dictionary (hash table, hash map)
g = {1: 'One', 2: 'Two', 3: 'Three'}
print(g[1]) # 'One'


1
1.0
Hello world
Привет, мир!
3
1
{1, 2}
One

Loops

for


In [8]:
for i in range(10):
    print(i)


0
1
2
3
4
5
6
7
8
9

while


In [9]:
i = 0
while i < 10:
    print(i)
    i += 1


0
1
2
3
4
5
6
7
8
9

Enumerate


In [10]:
items = ['apple', 'banana', 'stawberry', 'watermelon']
for item in items:
    print(item)


apple
banana
stawberry
watermelon

In [11]:
for i, item in enumerate(items):
    print(i, item)


0 apple
1 banana
2 stawberry
3 watermelon

Python code style

There is PEP 8 (Python Enhancement Proposal), which contains all wise ideas about Python code style. Let's look at some of them:

Naming


In [12]:
# Variable name
my_variable = 1

# Class method and function names
def my_function():
    pass

# Constants
MY_CONSTANT = 1


# Class name
class MyClass(object):
    # 'private' variable - use underscore before a name
    _my_variable = 1

    # 'protected' variable - use two underscores before a name
    __my_variable = 1

    # magic methods
    def __init__(self):
        self._another_my_variable = 1

String Quotes

PEP 8 quote:

In Python, single-quoted strings and double-quoted strings are the same. PEP 8 does not make a recommendation for this. Pick a rule and stick to it. When a string contains single or double quote characters, however, use the other one to avoid backslashes in the string. It improves readability.

For triple-quoted strings, always use double quote characters to be consistent with the docstring convention in PEP 257.

My rule for single-quoted and double-quoted strings is:

  1. Use single-quoted for keywords;
  2. Use double-quoted for user text;
  3. Use tripple-double-quoted for all multiline strings and docstrings.

In [13]:
'string'

"another string"

"""Multiline
string"""

'''
Another
multiline
string
'''


Out[13]:
'\nAnother\nmultiline\nstring\n'

Some tricks

Sum all elements in an array is straightforward:


In [14]:
sum([1,2,3,4,5])


Out[14]:
15

However, there is no built-in function for multiplication:


In [15]:
mult([1,2,3,4,5])


---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-15-8b055da1542b> in <module>()
----> 1 mult([1,2,3,4,5])

NameError: name 'mult' is not defined

, so we have to write our solution. Let's start with straightforward one:


In [16]:
def mult(array):
    result = 1
    for item in array:
        result *= item
    return result

In [17]:
mult([1,2,3,4,5])


Out[17]:
120

There is another way to implement it. It is to write it in a functional-programming style:


In [18]:
from functools import reduce

def mult_functional(array):
    return reduce(lambda prev_result, current_item: prev_result * current_item, array, 1)

In [19]:
mult_functional([1,2,3,4,5])


Out[19]:
120

In [20]:
%timeit mult(range(1, 1000))
%timeit mult_functional(range(1, 1000))


1000 loops, best of 3: 499 µs per loop
1000 loops, best of 3: 610 µs per loop

Python is really good for fast prototyping

Let's look at a simple problem (https://projecteuler.net/problem=5):

2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.

What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?

Brute force solution


In [21]:
def get_smallest_divisor_in_range(N):
    """
    Brute force all numbers from 2 to 1*2*3*4*5*6*...*N
    until we get a number, which divides by all numbers
    in a range of [1, N].
    
    Example:
    
    >>> get_smallest_devisor_in_range(10)
    2520
    """
    range_multiplied = mult(range(2, N+1))
    for x in range(2, range_multiplied, 2):
        for divisor in range(3, N+1):
            if x % divisor:
                break
        else:
            break
    return x

In [22]:
%time print(get_smallest_divisor_in_range(10))
%time print(get_smallest_divisor_in_range(20))


2520
CPU times: user 1.29 ms, sys: 19 µs, total: 1.31 ms
Wall time: 1.33 ms
232792560
CPU times: user 1min 44s, sys: 989 ms, total: 1min 45s
Wall time: 1min 53s

Faster solution for the problem

It is to count LCM (Least common multiple) of all numbers in a range of [1, N]:

$[a,b]=p_1^{\max(d_1,e_1)}\cdot\dots\cdot p_k^{\max(d_k,e_k)}.$

For example:

$8\; \, \; \,= 2^3 \cdot 3^0 \cdot 5^0 \cdot 7^0 \,\!$

$9\; \, \; \,= 2^0 \cdot 3^2 \cdot 5^0 \cdot 7^0 \,\!$

$21\; \,= 2^0 \cdot 3^1 \cdot 5^0 \cdot 7^1. \,\!$

$\operatorname{lcm}(8,9,21) = 2^3 \cdot 3^2 \cdot 5^0 \cdot 7^1 = 8 \cdot 9 \cdot 1 \cdot 7 = 504. \,\!$


In [23]:
def get_smallest_divisor_in_range_fast(N):
    """
    Optimal solution for the problem is to count
    LCM (Least common multiple) of all numbers in
    a range of [1, N].
    """
    prime_divisors = {}
    # Loop from 2 to N.
    for x in range(2, N+1):
        # Find and save all prime divisors of `x`.
        for divisor in range(2, int(x**0.5) + 1):
            power = 0
            # Find the power of the `divisor` in `x`.
            while x % divisor == 0:
                x /= divisor
                power += 1
            if power > 0:
                # Save the `divisor` with the greatest power into our `prime_divisors` dict (hash-map).
                if divisor in prime_divisors:
                    if prime_divisors[divisor] < power:
                        prime_divisors[divisor] = power
                else:
                    prime_divisors[divisor] = power
            # Stop searching more divisors if `x` is already equals to `1` (all divisors are already found).
            if x == 1:
                break
        else:
            # If `x` is prime, we won't find any divisors and
            # the above `for` loop will be over without hitting `break`,
            # thus we just need to save `x` as prime_divisor in power of 1.
            prime_divisors[x] = 1
    # Having all prime divisors in their lowest powers we multiply all of them to get the answer.
    least_common_multiple = 1
    for divisor, power in prime_divisors.items():
        least_common_multiple *= divisor ** power
    return least_common_multiple

In [24]:
%time print(get_smallest_divisor_in_range_fast(10))
%time print(get_smallest_divisor_in_range_fast(20))


2520
CPU times: user 238 µs, sys: 73 µs, total: 311 µs
Wall time: 318 µs
232792560
CPU times: user 381 µs, sys: 32 µs, total: 413 µs
Wall time: 5.35 ms

In [25]:
%time print(get_smallest_divisor_in_range_fast(10000))


57933396702876429686922708791662400986348602979985188253931383511489793001457731823088325981761829221665744176794023407056559491402467891577328326763021299466843118474637852656831938521549472347971073068161679301705472685236926463387338495220571064420250677315000599457941340849496227227628926493771018264821842230370349640102573492881424317306189569467101495834601991270039918780924506495405797923762205360790652073159333382795670426041033566699342449050309786673681670483369155689567554239898879039744147333971988258061042090970476729293484513072443614795766878726325795854855394491290821167148355514749149683707585283381546153703014210442470318180511906691108325146494219343498899382918018246586609827667470329166012110874981104800415741527586280026737848182673635645872230905234515169611121042867043956727839314198728626274066655467846183343599194761590368608472578398169740111485924046986870714883894285841394964627408094161019230662749101230783008668676907211199488107523306410531772045452853957706873238466829988649822157557103503283563398281775464911904789159515900987401574678885942493907604740891878907698622679570965569483682456042918236444719794534411171907606336090534029349351300276141892529795448751826394399153216183270385737795748770508612096374765333578237973395907265484337502903901947799663388329849198045756207969590055686607678195206367273600632909417024224754750428711236917913663419215925830944035539848749163178489614227546656090790164108195741048033614368495827231281392190063051315248070192263400801315095608512139510731469732311313898995746040563433121427776071482655904346538281010668476731132415829844984600414136781404774213539507859790229205890271721600309169926806121871750008163738773911610009508609149665332579632767397078877996926581337419351834754370411008686136818501030862345505385357198060894463821342298717851567836562984344806469613768024764967372979655179066074398198246805104576134474823016488842818077041661676098399378809713894284994865370648616800689225595431967181072865363430005250840767890912164530705704936837915584856606960687347372391339254432119085932175541392954343684716695162629271229789289404752104218596977036941910521266321726821940533986384237994403780618301379099347975260122724194454275088825587044488208965690373706904056926509324696308810974331790119456438147168585552011926921912167450509941646104076818762060881903969616431646384985895944231218505620547093874241169759205450145478746112796898626711966320965057212219958567338851356631739947125096250452942497473309299907612330435197454392788637359253116308685007014249605492659524429134513344137517101872279428202285951652856354827230765931502805341696470148698002737700823078904634554776750169178259216255903968865588749827789888950172452455448248833712309835657561369233157977405579365293671943131412034109901944892819245001657496671822581274180596255340507054499934060282320458240722454209933569735940032859109934686878274110864394924463573852015338428881961843292083566034669814619612606638283615766521897504566616272305253931938372830446073384019299355320864342734019517633662346790422915951954822645137091494126100390104510987373366328615363056042137440808225973600809566845718073791616927784260557845021823094999326904373592319407516660896764388092262510369182153559285446074990941863516247226532653142198551840063631989428776799533286215464660644129411503287306838551341184739976807097763115368031748646043780549055143428297230678053738453010234949008253769355207208167999203353157524666017029803679612131824740794652592875662818479980117505768541194835524231818203552256426752730455115752280837099763237606348192867936457993970866446264015812819179994138642295108872381709181937092290392544335464025324661284746003660247161196698209062164637264114930766444473471083408200329662059064201896721165015687487728300854501780810155844837489798144309942999091774466406270065305461848242329380636274754660519867343112275861821293501112101434868225378041813836808745417606289159904294165941408692922250601127804971962342807927743390030395048263275616935165347620718001157478088456439083590834464409622781693790883289597024043982584220069224170235863458745344365684082114430362867446193601075569803650773018026700003812298460527976219100308016537538008597751565631582745643139434508332515569645426771932483266712323523039014220800000
CPU times: user 341 ms, sys: 9.31 ms, total: 351 ms
Wall time: 485 ms

Even faster solution

(credits to Stas Minakov)


In [26]:
try:
    from math import gcd
except ImportError:  # Python 2.x has `gcd` in `fractions` module instead of `math`
    from fractions import gcd

def get_smallest_divisor_in_range_fastest(N):
    least_common_multiple = 1
    for x in range(2, N + 1):
        least_common_multiple = (least_common_multiple * x) // gcd(least_common_multiple, x)
    return least_common_multiple

In [27]:
%time print(get_smallest_divisor_in_range_fastest(10))
%time print(get_smallest_divisor_in_range_fastest(20))


2520
CPU times: user 569 µs, sys: 630 µs, total: 1.2 ms
Wall time: 919 µs
232792560
CPU times: user 55 µs, sys: 1 µs, total: 56 µs
Wall time: 62 µs

In [28]:
%time print(get_smallest_divisor_in_range_fastest(10000))


57933396702876429686922708791662400986348602979985188253931383511489793001457731823088325981761829221665744176794023407056559491402467891577328326763021299466843118474637852656831938521549472347971073068161679301705472685236926463387338495220571064420250677315000599457941340849496227227628926493771018264821842230370349640102573492881424317306189569467101495834601991270039918780924506495405797923762205360790652073159333382795670426041033566699342449050309786673681670483369155689567554239898879039744147333971988258061042090970476729293484513072443614795766878726325795854855394491290821167148355514749149683707585283381546153703014210442470318180511906691108325146494219343498899382918018246586609827667470329166012110874981104800415741527586280026737848182673635645872230905234515169611121042867043956727839314198728626274066655467846183343599194761590368608472578398169740111485924046986870714883894285841394964627408094161019230662749101230783008668676907211199488107523306410531772045452853957706873238466829988649822157557103503283563398281775464911904789159515900987401574678885942493907604740891878907698622679570965569483682456042918236444719794534411171907606336090534029349351300276141892529795448751826394399153216183270385737795748770508612096374765333578237973395907265484337502903901947799663388329849198045756207969590055686607678195206367273600632909417024224754750428711236917913663419215925830944035539848749163178489614227546656090790164108195741048033614368495827231281392190063051315248070192263400801315095608512139510731469732311313898995746040563433121427776071482655904346538281010668476731132415829844984600414136781404774213539507859790229205890271721600309169926806121871750008163738773911610009508609149665332579632767397078877996926581337419351834754370411008686136818501030862345505385357198060894463821342298717851567836562984344806469613768024764967372979655179066074398198246805104576134474823016488842818077041661676098399378809713894284994865370648616800689225595431967181072865363430005250840767890912164530705704936837915584856606960687347372391339254432119085932175541392954343684716695162629271229789289404752104218596977036941910521266321726821940533986384237994403780618301379099347975260122724194454275088825587044488208965690373706904056926509324696308810974331790119456438147168585552011926921912167450509941646104076818762060881903969616431646384985895944231218505620547093874241169759205450145478746112796898626711966320965057212219958567338851356631739947125096250452942497473309299907612330435197454392788637359253116308685007014249605492659524429134513344137517101872279428202285951652856354827230765931502805341696470148698002737700823078904634554776750169178259216255903968865588749827789888950172452455448248833712309835657561369233157977405579365293671943131412034109901944892819245001657496671822581274180596255340507054499934060282320458240722454209933569735940032859109934686878274110864394924463573852015338428881961843292083566034669814619612606638283615766521897504566616272305253931938372830446073384019299355320864342734019517633662346790422915951954822645137091494126100390104510987373366328615363056042137440808225973600809566845718073791616927784260557845021823094999326904373592319407516660896764388092262510369182153559285446074990941863516247226532653142198551840063631989428776799533286215464660644129411503287306838551341184739976807097763115368031748646043780549055143428297230678053738453010234949008253769355207208167999203353157524666017029803679612131824740794652592875662818479980117505768541194835524231818203552256426752730455115752280837099763237606348192867936457993970866446264015812819179994138642295108872381709181937092290392544335464025324661284746003660247161196698209062164637264114930766444473471083408200329662059064201896721165015687487728300854501780810155844837489798144309942999091774466406270065305461848242329380636274754660519867343112275861821293501112101434868225378041813836808745417606289159904294165941408692922250601127804971962342807927743390030395048263275616935165347620718001157478088456439083590834464409622781693790883289597024043982584220069224170235863458745344365684082114430362867446193601075569803650773018026700003812298460527976219100308016537538008597751565631582745643139434508332515569645426771932483266712323523039014220800000
CPU times: user 132 ms, sys: 5.21 ms, total: 137 ms
Wall time: 307 ms

Very important references


In [ ]:
import math
math?