字串函數 & 函數呼叫

Arvin Liu @ Sprout

聊天板

tlk.io/clang

匿名的唷!

10.5.6.94:8788

點名網址

xx.x.x.xx:8788/recorder

查看><

Function Call

什麼是函數?

一元一次函數

f(x) = x + 1

f(2) = 3

數學上...

二元函數

f(x,y) = x + y + xy + 1

f(2,3) = 12

數學上...

f(x,y) = x + y + xy + 1

有那麼一點機會在數學上...

f(x,y)

x

y

結果

f(x,y) = x + y + xy + 1

有那麼一點機會在數學上...

f(x,y)

2

3

12

f(x,y) =

那有沒有機會這個f箱子

f(x,y)

出去操場跑三圈

宅在家裡看電視一天

最後給你x+y+xy+1。

有可能嘛(笑)

你又不知道他裡面在幹嘛?
反正結果符合你的預期就好啦~

就是你呼叫了之後,

它會做一些固定的事情,
最後(可能會)給你一個值。

所以函數...

舉個例子

puts: (put string)
給一個字元陣列,
輸出這個字元陣列和換行。

舉個例子

做事: 輸出你給的字。
回傳:錯誤給-1,
正常給非負的值。

為什麼需要函數?

比較好看

但是你不知道你用的那個人做了什麼。

&

不用重寫

怎麼用別人的函數啊?

#include <函式庫名稱>

Step 1 - 知道別人在哪裡 /
告訴編譯器你要用哪裡的函數

函式庫:放很多個函式的倉庫。

#include <iostream>就是一種。

strlen -> #include<cstring>
Sleep -> #include <windows.h>

Step 1 - Example

Step 2 - 知道別人要什麼

f(x) = x^2 + x + 1

只吃float/double/int

f("我好帥")

<- 編譯錯誤

String review

偷渡指標的概念...

char A[] = "123456789";
std::cout << A << std::endl;
std::cout << A+3 << std::endl;
std::cout << A+6 << std::endl;
Output:
123456789
456789
789

偷渡指標的概念...

char A[] = "123456789";
std::cout << A << std::endl;
std::cout << A+3 << std::endl;
std::cout << A+6 << std::endl;
1 2 3 4 5 6 7 8 9 '\0'

A

A+3

A+6

str func - review

要#include <cstring>喔!

strlen(char [])

回傳這個字串的長度。

Example

char S[100];
cin >> S;
cout << strlen(S);
Input:
abcdef
Output:
6

Warning!

for(int i=0; i< strlen(S); i++)
    // do something
int len = strlen(S);
for(int i=0; i< len ; i++)
    // do something

Maybe TLE (它其實是個雙層迴圈)

Maybe AC

strcmp(char [],char [])

回傳 0 表示這兩個字串一樣。

Example

char S[100];
cin >> S;
cout << (strcmp(S,"QAQ") == 0);
Input:
abcdef
-------
QAQ
Output:
0
----
1

Warning!

if("ABCD" == S){
    // Do something.
}

不會CE,但是結果不一樣。

詳情請見指標。

str func - new

要#include <cstring>喔!

strcat(char [],char [])

把後面的字串接在前面

Example

char str[80];
strcpy (str,"these ");
strcat (str,"strings ");
strcat (str,"are ");
strcat (str,"concatenated.");
puts (str);
Output:
these strings are concatenated.

strcpy(char [],char [])

把後面的字串覆蓋前面的字串。

Example

char str1[] = "Sample string";
char str2[40];
strcpy (str2,str1);
puts (str2);
Output:
Sample string

Review

  • strcmp - string compare
  • strcat - string concatenate
  • strcpy - string copy
  • strlen - string length

Practice!

可以嘗試用

剛剛說的函數
做做看喔!

Problem Description

Solution Explanation

0123456789
9012345678
8901234567
7890123456
6789012345
5678901234
4567890123
3456789012
2345678901
1234567890

S+len-1

S+len-2

S+len-3

S+len-4

Solution Explanation

01234567890
901234567890
8901234567890
78901234567890
678901234567890
5678901234567890
45678901234567890
345678901234567890
2345678901234567890
12345678901234567890

strcat

Solution Explanation

'\0'

01234567890
901234567890
8901234567890
78901234567890
678901234567890
5678901234567890
45678901234567890
345678901234567890
2345678901234567890
12345678901234567890

Answer

#include <iostream>
#include <cstring>
using namespace std;
int main(){
    char S[1001],S2[2001];
    cin >> S;
    int len = strlen(S);
    for( int i = len-1 ; i>=0 ; i-- ){
        strcpy(S2,S+i);
        strcat(S2,S);
        S2[len] = 0;
        cout << S2 << endl;
    }
}

嘗試用你的code
解出上週的marquee吧!

Hint: 外面一層while迴圈,每次輸出都Sleep,最後在換行的地方改成回車符號。

Homework Solution

Step 1 - 如何存咒語?

咒語大全有
很多個咒語
(100)

每個咒語有

很多字節
(100)

每個字節

有很多
(20)

char Spell_book [100][100][161];

Step 1 - 如何存咒語?

咒語大全中
第i個咒語的

第j個字節的
第k個char

Spell_book [i][j][k]

Step 2 - 比較兩個字節是否一樣

咒語大全中

第i個咒語和第j個咒語

的第k個字節一不一樣?

strcmp( Spell_book [i][k],
Spell_book [j][k] ) 是不是0

Step 3 - 找出最長的重複前綴

假如我們要找第i個咒語的縮略,
那麼讓第 i 個咒語和其他字串找重複前綴。

答案就是最長的那個 + 1 。

Solution Code

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
char S[100][100][161];
int main(){
    int N;
    cin >> N;
    for(int i=0;i<N;i++){
        int M;
        cin >> M;
        for(int j=0;j<M;j++){
            cin >> S[i][j];
        }
    }
    for(int i=0;i<N;i++){
        int max_match = 0;
        for(int j=0;j<N;j++){
            if(i == j)
                continue;
            else{
                for(int k=0;k<100;k++){
                    if(strcmp(S[i][k],S[j][k])!=0){
                        max_match = max(max_match,k);
                        break;
                    }
                }
            }
        }
        cout << max_match +1 << endl;
    }
    return 0;
}

快,還要更快。

(Optional)
字串用hash比對。
複雜度降一個O(|S|)

(Optional)
Trie的方式做整個咒語寶典。
其中分岔用map。
複雜度把一個O(N)降O(lgN)

以上兩個技巧的複雜度是O(NMlogN + NM|S|)

(Optional)
用Radix Sort做排序,
再用二維Hash做二分搜

複雜度
O(NM|S| + NlogM)