最近在論壇閑逛,先后參與了兩題算法趣味題目。
- 題目1是要求算一任意長度字符串中不同的字符以及它的個數。
- 題目2是把一段字符串用“右起豎排”的古文格式輸出。
題目難度不大,都是針對字符串的操作,邏輯比較簡單,靈活在對不同語言、語法的掌握程度。(原文分別在:1,2。)
看了大家用C++、C#、Java等語言的實現,總感覺牛刀殺雞太麻煩,有興趣的朋友可以自己寫寫看或者直接看原文的網友回復。我最近一段時間Python寫的比較多,讀到這些題目時候,就有一種躍躍欲試的沖動。因為我知道用Perl,Python,Ruby等動態語言來做這類題目,會是非常理想的。后來我做了這兩道題目,結果也令人滿意,代碼之簡潔保持在所有答案的前列。
先看第一題Python解答:
dic = {}
for s in "abcdefgabc":
dic[s] = 1 if s not in dic else (dic[s]+1)
print '\n'.join('%s,%s' % (k, v) for k, v in dic.items())
輸出結果:
a,2
c,2
b,2
e,1
d,1
g,1
f,1
Python的四行代碼分別做了dictionary的聲明,賦值,字符串的遍歷,以及高效拼接。
如果還沒有看出它的簡潔和強大的話,請看第二題的解法:
def main(offset=6):
string = u'靜夜思 李白床前明月光,疑似地上霜。舉頭望明月,低頭思故鄉。090131'
a = [[' ']*offset for row in xrange(offset)]
for i in xrange(offset):
for j in xrange(offset):
a[i][j] = string[j + i*offset]
b = [[r[col] for r in a[::-1]] for col in xrange(len(a[0]))]
print '\n'.join([u'┊'.join(unicode(c) for c in row)for row in b])
輸出結果:
0┊低┊舉┊疑┊床┊靜
9┊頭┊頭┊似┊前┊夜
0┊思┊望┊地┊明┊思
1┊故┊明┊上┊月┊
3┊鄉┊月┊霜┊光┊李
1┊。┊,┊。┊,┊白
這題如果用C#等實現,代碼要在20行以上。下面我簡單介紹一下這幾行代碼:
- 第3行,在Python里面二維“數組”通過嵌套list來實現,這里初始化一個6行6列的二維數組;
- 第7行,我們把“矩陣”順時針旋轉了90度(行列置換,并且對置換后的行首尾對調-這里的::-1就是用來置換一個list的trick);
- 最后一行,我們把數組里的每行中元素,每行之間分別用兩個不同字符拼接起來。join方法以及for..in..語句在python中是相當常見的用法。
通過這兩題,我們看到Python在處理字符串時候的十分靈活方便,雖然一種語言的好壞不應完全靠是否簡潔來衡量,但對于我個人而言,Python是目前我用過的最好的語言。而且對于趣味題來說,這不就是我們解題的趣味所在嗎?
Feedback
老趙的代碼不錯,我改進下
第二個
static void Count(string message) {
message
.GroupBy(c => c)
.ToList()
.ForEach(p => Console.WriteLine("{0}, {1}", p.Key, p.Count()));
}
這樣似乎更爽一些,呵呵
@JimLiu
那個select的確可以省,我是習慣于先搞出數據來,然后添加行為,而不是在行為里繼續計算
@Jeffrey Zhao
呵呵,是因為先select了好重復用吧,習慣問題,我的喜歡就根據題目變化。
a="abcdefgabc"
myset=set(a)
for s in myset:
print(str(a.count(s))+" "+s)
2 a
2 c
2 b
1 e
1 d
1 g
1 f
import math
colSize=6
string="靜夜思 李白床前明月光,疑似地上霜。舉頭望明月,低頭思故鄉。0901311"
iLen=math.ceil(len(string)/colSize)
l=list(reversed(([string[i*colSize:i*colSize+colSize].ljust(colSize,' ') for i in range(0,iLen)])))
for i in range(colSize):
for j in range(iLen):
print(l[j][i],end=" ")
print()
python語法我真的快忘光光了.
PHP的:
$a="abcdefgabc";
$result=count_chars($a,1);
array_walk($result,create_function('$v,$k','echo chr($k)." ".$v."<br/>";'));
a 2
b 2
c 2
d 1
e 1
f 1
g 1
JavaScript:
var s = "hello";
var arr = s.split('');
var o = {};
var c;
for (var i = 0; i < arr.length; i++)
{
o[arr[i]] = (o[arr[i]] ? o[arr[i]] : 0) + 1;
}
var result = "";
for (var p in o)
{
result += p + ", " + o[p] + "\r\n";
}
alert(result);
>>> from collections import defaultdict
>>> adict = defaultdict(int)
>>> for s in "abcdefgabc":
... adict[s] += 1
...
>>> print '\n'.join('%s,%s' % (k, v) for k, v in adict.iteritems())
a,2
c,2
b,2
e,1
d,1
g,1
f,1
a="abcdefgabc"
b={}
a.each_char { |x|b.store(x,a.count(x)) }
b.each {|k,v| puts k+" "+v.to_s}
試試Groovy:
('abcdefgabc' as List).groupBy{it}.each{k, v -> println "$k, ${v.size()}"}
試試Groovy(第二題):
def a = '床前明月光 疑似地上霜 舉頭望明月 低頭思故鄉'.tokenize(' ')
5.times{row ->
println a.collect{it[row]}.reverse().join('|')
}
低|舉|疑|床
頭|頭|似|前
思|望|地|明
故|明|上|月
鄉|月|霜|光
txt = u"靜夜思 李白床前明月光,疑似地上霜。舉頭望明月,低頭思故鄉。"
offset = 6
a =[i[::-1] for i in zip(*[txt[i:i+offset] for i in range(0, len(txt), offset)])]
for i in a:
print "|".join(i)