美文网首页
写给数学爱好者以及妹子们的编程入门教程

写给数学爱好者以及妹子们的编程入门教程

作者: zzz雪人 | 来源:发表于2017-10-04 20:34 被阅读75次

好的,一起进入教程的米娜桑,第一步,先买一台Macbook,没错出门右转先去买电脑。
好的,我们继续,第一步现在你的电脑上安装brew,因为以后我们安装万物都需要他。

打开你的终端(terminal),command+space

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

把他复制到终端里,大力按回车。

安装zsh,让你的terminal变炫酷
sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"

接下来,打开一个窗口,输入

brew cask install atom

这是一个代码编辑器,恩,丑的人用IDE(集成开发环境),我们喜欢数学的帅的人用编辑器。

以后我们运行代码,只需要用编辑器编辑好你的代码命名为,supercool.rb,然后在命令行里用cd(进入文件夹)到你这个源码所在的文件夹里,输入ruby supercool.rb就可以运行了。

从著名招聘网站https://leetcode.com里选个编程题目来入门好了,我觉得我们还是从丑的开始搞吧。。。

第一题

263. Ugly Number

Write a program to check whether a given number is an ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 6, 8 are ugly while 14 is not ugly since it includes another prime factor 7.
Note that 1 is typically treated as an ugly number.

我不会给你解释题目,因为爱好数学的你早晚要过英文关,这里我就推荐个有道词典给你安装好了。

为什么之前让你这么麻烦,因为以后你安装软件就是一个命令就能搞定了,不用打开网页,再下载,再安装。

打开一个termianl窗口,输入

brew cask install youdaodict

Vue(不好意思我是一个前端框架Vue.js的脑残粉)的一下你的软件就安装好了,下面你把他拖到下面那个DOCK栏,方便以后使用。

理解题目就可以撸起袖子跟着习主席一起干了。

既然是检测一个数是否是丑陋的数,我们就写一个函数来完成它好了。

def is_ugly(n)
  
end

这是程序世界定义函数的方法,名字就是is_ugly,后面那个n代表输入值,就像函数的因变量,你输入一个数,我的函数来判断他是否丑陋就OK了。

既然我们要寻找的是很丑陋的数,那品味挑剔的我想,这世界大多数的人都很丑吧。。。。那么我们第一个版本的函数就来默认所有输入的数都很丑陋好了。。。


def is_ugly(n)
  true
end

这里你看到函数体里面多了一个逻辑变量true,没错我们很高贵,高贵到我们用的语言叫做Ruby(红宝石),在红宝石里,这一个true代表的是我们这个函数返回值是true,什么叫做返回值呢?没错一个函数有自变量当然要有因变量,这个返回值可以类比为因变量,就是输出的结果罢了。

一个严重的问题!但是我们现在的程序貌似什么都不显示啊。。。。

想显示东西,我们就加一句打印,就有东西出现了

print is_ugly(13)

然而13并不是一个丑陋的数,上文里我任性了,看来这世界上的丑人真的是极品中的极品啊!这么难找!

我噻,改代码!

def is_ugly(n)
  false
end

print is_ugly(13)

这下我们的程序起码在输入值是13的时候是正确的。

下一个版本

def is_ugly(n)
  if (n % 2 === 0)
  true  
  else
  false
  end
end

其实这段代码就和英语的意思是差不多的。。。%代表的是取余数,比如1%3就是1,2%3就是2,4%3就是1。

在这里我想插一句重要的话。

代码就是你的试验场,你什么不会可以试试看,在我们小时候第一次打开积木的包装盒的时候,我们是完全不会的,但是玩是人的本能,我们就瞎几把弄,有的时候还能架起高高的小楼呢。

打开一个终端,输入irb回车。

你就进入了一个试验场,你可以输入1%3看看结果是什么。我一直认为自己瞎几把玩是学习的最快方式。

这段代码又有一个连续的等号有人要问啥意思了。

很简单,一个等号代表的是赋值,a = 1是把让。。。。好吧,咔!先停住,别想那么多了,我这段代码的意思就是这么简单,如果输入的n除2的余数是0就返回true,其他情况(else)的话就返回false。

我们来看看输出如何

print is_ugly(2) #2 is ugly
print is_ugly(3) #3 is ugly
print is_ugly(4) #4 is ugly
print is_ugly(5) #5 is ugly
print is_ugly(6) #6 is ugly
print is_ugly(7) #7 is not ugly

运行看看结果

➜  rb ruby 263-Ugly-Number.rb
truefalsetruefalsetruefalse%       

这个第二个错了,那么我们重新修改代码。

def is_ugly(n)
  if (n % 2 === 0) or (n % 3 === 0 and is_ugly(n / 3))
  true  
  else
  false
  end
end

修改代码的时候我们注意到两个问题。

最重要的一点,各位有没有发现我的做法是先写测试代码,发现有问题就修改代码,让他正确,没错这个在软件开发里算是一个时髦的词汇叫做TDD(Test-Driven Development)各位不必深究,我不过想让自己看得高大上一点而已。

第二件事,在修改的代码里,我在函数体内调用了函数本身。这叫做递归。

其实不用想太多,我们这个函数的目的是为了判定一个数是否是丑陋的数,那我想做的事(通过(n % 3 === 0 and is_ugly(n / 3))就是如果过这个数能整除3的话,他除以3之后的数还是丑陋数的话,就能通过我们评判是否丑陋的这一关。

所以这么写从字面角度考虑完全符合逻辑,你就别瞎想了,没问题的。

之后我又写了下测试

print is_ugly(2) #2 is ugly
print is_ugly(3) #3 is ugly
print is_ugly(4) #4 is ugly
print is_ugly(5) #5 is ugly
print is_ugly(6) #6 is ugly
print is_ugly(7) #7 is not ugly
print is_ugly(21) # false

尴尬的发现我们现在的代码好丑(有种挖东墙补西墙的赶脚),懒得重构了,咱们重写好了!

写程序讲究一气呵成。


def is_ugly(num)
  if num <= 0
    false
  elsif num == 1
    true
  elsif num == 2
    true
  elsif num == 3
    true
  elsif num == 5
    true
  elsif
    ((num % 2 == 0) and (is_ugly(num / 2))) or 
    ((num % 3 == 0) and (is_ugly(num / 3))) or
    ((num % 5 == 0) and (is_ugly(num / 5)))
    true
  else
    false
  end
end


在leetcode网站里,提交这段代码,是可以通过的。

下一个问题!Super Ugly Number II

Write a program to find the n-th ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.
Note that 1 is typically treated as an ugly number, and n does not exceed 1690.

打开命令行(终端)

➜ rb atom 264-ugly-2.rb

这个atom就是我开始安装的编辑器,他来自Facebook,我是FB的脑残粉。

看下我第一个版本的代码

# @param {Integer} n
# @return {Integer}
def nth_ugly_number(n)
  while (n >= 0)
  end
end

nth_ugly_number(1)

def is_ugly(num)
  if num <= 0
    false
  elsif num == 1
    true
  elsif num == 2
    true
  elsif num == 3
    true
  elsif num == 5
    true
  elsif
    ((num % 2 == 0) and (is_ugly(num / 2))) or
    ((num % 3 == 0) and (is_ugly(num / 3))) or
    ((num % 5 == 0) and (is_ugly(num / 5)))
    true
  else
    false
  end
end

这个while的意思就是当括号里的内容正确,就不断重复这while体内的代码。

我把之前的代码也弄下来是想要复用他。

这段代码的结果?好像啥都没(因为while括号里的内容永远都是正确的,他就一直这么循环下去了),咱接着改。

# @param {Integer} n
# @return {Integer}
def nth_ugly_number(n)
  while (n >= 0)
    n = n - 1
  end
end

nth_ugly_number(1)


def is_ugly(num)
  if num <= 0
    false
  elsif num == 1
    true
  elsif num == 2
    true
  elsif num == 3
    true
  elsif num == 5
    true
  elsif
    ((num % 2 == 0) and (is_ugly(num / 2))) or
    ((num % 3 == 0) and (is_ugly(num / 3))) or
    ((num % 5 == 0) and (is_ugly(num / 5)))
    true
  else
    false
  end
end

这下咱们应该可以刹住车了,1带入这个方程满足n>=0,但是接着n就会不断地递减,到-1就不满足条件了,咱们就能刹车了。

但是运行这段代码

➜  rb ruby 264-ugly-2.rb
264-ugly-2.rb:8:in `nth_ugly_number': undefined method `is_ugly' for main:Object (NoMethodError)
from 264-ugly-2.rb:15:in `<main>'

表示is_ugly未被定义,这样就把is_ugly的定义体放到最前就好了。


def is_ugly(num)
  if num <= 0
    false
  elsif num == 1
    true
  elsif num == 2
    true
  elsif num == 3
    true
  elsif num == 5
    true
  elsif
    ((num % 2 == 0) and (is_ugly(num / 2))) or
    ((num % 3 == 0) and (is_ugly(num / 3))) or
    ((num % 5 == 0) and (is_ugly(num / 5)))
    true
  else
    false
  end
end



# @param {Integer} n
# @return {Integer}
def nth_ugly_number(n)
  number = 0
  while (n >= 0)
    number = number + 1
    if (is_ugly(number))
      n = n - 1
    end
  end
  number
end

我这里用的算是最傻逼的寻找第n个丑陋数的方法,在leetcode里跑一下,发现超时了。。。。

没错,我们的代码其实是OK的,但是这个平台很挑剔,但是我很懒
我只求能够把问题解决就OK了,
于是我找了哥们zsy的解法
大家感受下有ruby香味的代码。


# @param {Integer} n
# @return {Integer}
def nth_ugly_number(n)
  a, b, c = [], [], [] 
  current = 1
  counter = 1
  while counter < n
    a.push current * 2
    b.push current * 3
    c.push current * 5
    current = [a[0], b[0], c[0]].min
    a = a[1..-1] if current == a[0]
    b = b[1..-1] if current == b[0]
    c = c[1..-1] if current == c[0]
    counter += 1
  end
  current
end

哇塞,连颜色都变了呢!是不是很神奇!

我突然在想一个问题,各位数学爱好者是不是被我弄得很难受?我们现在代码就算不丑,用代码干的事却是找最丑陋的数。

那我们就来解决哥德巴赫猜想好了。

哥德巴赫另外的一个猜想(Goldbach's other conjecture)。

It was proposed by Christian Goldbach that every odd composite number can be written as the sum of a prime and twice a square.
9 = 7 + 2×12
15 = 7 + 2×22
21 = 3 + 2×32
25 = 7 + 2×32
27 = 19 + 2×22
33 = 31 + 2×12 (后面的2代表二次方)
It turns out that the conjecture was false.
What is the smallest odd composite that cannot be written as the sum of a prime and twice a square?

So from now on, we are tackling with an interesting problem, it's so interesting that I decide to use English to show off.
Actually this problem is so straight-forward, you can write your own version, I'll wait you here....

Beep!! Let's see how @peterkhayes solve this problem using Ruby.

# Problem number 46: Goldbach's other conjecture.

def prime?(num)
    return true if num == 2

    for i in (2..num**(0.5))
        return false if num % i == 0
    end
    return true
end

def twice_a_square?(num)
    return false if num % 2 == 1
    root = ((num/2)**(0.5)).to_int
    return true if 2*(root**2) == num
    false
end

def goldbach2_test(num)
    for i in (2..(num-1))
        if prime?(i)
            r = (num - i)
            if twice_a_square?(r)
                return true
            end
        end
    end
    return false
end

idx = 3
while true
    if !prime?(idx)
        break if !goldbach2_test(idx)
    end
    idx += 2
end
puts idx

Remember to use Google when you(always) bump into a problem, that's the basic of becoming a coder.

So here, we have three function, the first one is used to test whether a number is a prime number, the second one is used to test whether a number is a 2的平方数(forgive me...)

num**(0.5),突然发现装逼值不够(不知道怎么说num的0.5次方。。。)num的二分之一次方,就是num开根号。

return false if num % 2 == 1 算是一个短路判断,如果这个数被2除余一,那肯定不是2的平方数。这句判断写在这可以提高程序运行效率,像上一道题,我就因为程序速度慢导致超时。。。

这里idx = 3从3开始试验,每次给idx递增2,因为如果是偶数,肯定不满足条件,这也是提高程序运行效率的小技巧。

for i in (2..(num-1)) 是一个Ruby味道的写法,在ruby里如果写(2..5),他就给你一个数组[2,3,4,5],这些你都可以在irb里试验,for i in 一个数组,就是让i每一次等于数组里的一个数(按顺序),其实读起来和英语挺像的。

我觉得如果是女孩子的话可以猜到这句话的意思return true if num == 2 其实就是把if后置了,等同于

if num == 2
  return false

在结束之际,我想告诉大家为什么刚才在解释===的时候我这么墨迹,因为现在编程大方向有两个,FP和OOP,我推荐大家喜欢数学的直接走FP这条路,因为这很适合你,也是未来的趋势。在FP里,一个等号,很有可能并不是简单的的赋值的意思,而是简单的匹配的意思(比如Elixir),这个语言的中文意思就是长生不老的药水,怎么样我先带大家感受了红宝石,又介绍大家这个,品味还可以吧哈哈,并没有从土土的C/C++开始。

那么之前那个Ugly Number系列还有最后一道题,第三道,我看了下貌似是Goldman Sachs(某投行?)的面试题,为了避免各位这么快抢走我们程序员的饭碗,我就打住好了。。。。(其实是我不会hhhhhhhhh)

相关文章

网友评论

      本文标题:写给数学爱好者以及妹子们的编程入门教程

      本文链接:https://www.haomeiwen.com/subject/qwlxyxtx.html