這是一種方式,我們還可使用另外一種方式:
process.stdin.resume(); process.stdin.setEncoding('ascii'); var input = ""; var input_array = ""; process.stdin.on('data', function (data) { input += data; }); process.stdin.on('end', function () { input_array = input.split("\n"); var str = input_array[0]; console.log(str.split(' ').reverse().join(' ')); });
這種方式比之前的那種方式會更好一些! 即data事件的時候,我們一直處於接受數據的時候,然后一旦觸發了 end 事件,說明我們這次的輸入結束。 然后呢, 得到的 input_array就是輸入的所有行,我們直接使用就可以了。
其實,我們可以知道牛客網的方式應該是每次測試用例每次就調用函數。
說明: 后者為什么好呢? 因為通過后者,我們可以准確地判斷出來到底什么時候結束,而前者在某些情況下,我們是無法判斷函數是何時結束的,如下所示:
如果我們不用后者這種方式,那么我們就沒有辦法確定一共有多少個case,就沒法做這道題了。
最終ac的代碼如下所示:
process.stdin.resume(); process.stdin.setEncoding('ascii'); var input = ""; var input_array = ''; process.stdin.on('data', function (data) { input += data; }); process.stdin.on('end', function () { // 目前的這個input_array就是輸入的所有行,我們現在的目的就是如果把這兩個case放在一個一個數組中。 input_array = input.split("\n"); var nLine = 0; var hhh = []; while(nLine < input_array.length){ var line = input_array[nLine++].trim();
// 這一句非常關鍵,有了這一句,因為有時候,這個沒有處理好,可能輸入就會出現問題。 if(line === ''){ continue; }
// 這種方式我們就可以把輸入的所有行通過 hhh 這個數組來拿到了。
hhh.push(line); } var arr = []; for (var i = 0; i < hhh.length; i++) { // 當輸入是一個數字的時候,就是M或者是N 下面的isNaN(Number(hhh[i]))的判斷非常重要,通過這一句,我們就可以很輕松地來分類了 。 if (!isNaN(Number(hhh[i]))) { arr.push(hhh.slice(i + 1, i + Number(hhh[i]) + 1)); } } // 循環之后,得到的數組就是一個二維數組,一定是偶數個,比如arr數組的第一個元素就是['aaa', 'aaa', 'baa'], 那么arr的第二個元素就是 ['aa', 'ba'] var result = []; // 創建一個用於最后輸出的元素的數組,最終遍歷輸出即可。 for (var j = 0; j < arr.length; j++) { if (j % 2 == 0) { for (var k = 0; k < arr[j + 1].length; k++) { var count = 0; for (var m = 0; m < arr[j].length; m++) {
// 這里也很巧妙,就是對於一個字符串是否是另一個字符串的子串,我們可以通過 indexOf 的方式來解決,這樣就不需要耗時的遍歷的方法或者使用復雜的KMP算法了。 if (arr[j][m].indexOf(arr[j + 1][k]) != (-1)) { count++; } } result.push(count); } } } for (var n = 0; n < result.length; n++) { console.log(result[n]); } });
第一部分:
1. 360、完美世界等使用的編程環境(OJ系統)
http://oj.acmcoder.com/ExamNotice.html 對於OJ系統進行了說明。
http://oj.acmcoder.com/QA/ 常見問題
下面的代碼輸出的是a+b, line是用於輸入的。
var line; while(line = read_line()){ line = line.split(' '); print(parseInt(line[0]) + parseInt(line[1])); }
下面是一個成功運行的題目,如下:
注意的幾個地方:
- read_line() 得到的是輸入的字符串,如 "81 4"
- 顯然,通過read_line().split(" ")得到的是一個字符串數組(注意: split(" ")中有一個空格),所以如果我們希望使用數字,就應該Number轉換一下
- print()就相當於console.log(somethin); 再加一個<br/>(換行)。
- 最好使用上述固定的格式: 即在while循環內調用函數,在調用的函數里輸出。
- 對於本題而言,應當注意 toFixed() 是用在最后, 這才是最精確的。
下面的是將輸出使用空格分開,我最后的正確率是88%,不知道具體錯在了哪里...
2.網易使用的編程環境(牛客網提供OJ系統)
https://www.nowcoder.com/discuss/276
https://www.nowcoder.com/test/question/0147cbd790724bc9ae0b779aaf7c5b50?pid=2811407&tid=7485771 和網易的題是類似的
var readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout }); rl.on('line', function(line){ var tokens = line.split(' '); console.log(parseInt(tokens[0]) + parseInt(tokens[1])); });
第一句是指引入了readline文件,第二句是指設定rl的輸入輸出為標准輸入輸出。第三句的意思就是輸入為line的函數,第四句的意思就是將輸入以空格分為數組。 第五句就是使用console.log()輸出。
它的測試方法是,輸入大量的數據進行測試,並不是說只要有一個成立就行,而是所有的情況都成立才可以。
對於單行輸入,使用下面的方法:
即引入readline模塊,然后使用createInterface創建接口,接着使用on監聽line事件。 對於多行輸入的,我們可以用一個數組接受多行,等到滿足了長度,就執行主要的函數。
var readline = require('readline'); var rl = readline.createInterface({ input: process.stdin, output: process.stdout }); rl.on('line', function (line) { var str = line; var obj = {}; for (var i = 0, len = str.length; i < len; i++) { if (!obj[str[i]]) { obj[str[i]] = 1; } } var count = 0; for (var key in obj) { count++ } switch (count) { case 1: console.log(1); break; case 2: console.log(2); break; default: console.log(0); return; } });
下面是一個多行輸入的題目,題目如下:
解答過程如下:
var readline = require('readline'); var rl = readline.createInterface({ input: process.stdin, output: process.stdout }); var inputArr = []; rl.on('line', function (line) { inputArr.push(line.trim()); if (inputArr.length == 2) { var number = parseInt(inputArr[0]); var arr = inputArr[1].split(' '); // 首先將數組由小到大進行排列,這樣,d只可能是0或者正數。 arr.sort(function (a, b) { return a - b; }); var diff = []; for (var i = 0, len = arr.length; i < len - 1; i++) { diff.push(arr[i + 1] - arr[i]); } var flag = true; for (var j = 0, jLen = diff.length; j < jLen - 1; j++) { if (diff[j + 1] !== diff[j]) { flag = false; break; } } if (flag) { console.log('Possible') } else { console.log('Impossible'); } } });
即在readline.on('line', function (line) {})函數中使用inputArr.length來判斷是否等於輸入的行數,等於的時候,再執行主要邏輯。
看到了下面這種方式,其實也是蠻不錯的:
即處理好輸入之后,調用一個函數,這樣,我們在本地調試的時候,直接copy這個函數過去就可以了, 非常清楚明了。
3.牛客網上的劍指offer方法又略有不同:(OJ系統)
例: 這里實現的是將一個字符串中的空格使用%20替換。
function replaceSpace(str) { // write code here
} module.exports = { replaceSpace : replaceSpace };
這里最后只要在函數內return 出希望返回的值即可。
第二部分: 答題需要的基本知識
http://nodejs.cn/api/readline.html#readline_class_interface
一、nodejs中readline模塊的使用
一般,我們在使用系統進行答題時,都是需要使用readline模塊的,這個模塊可以進行讀取行,然后就可以由系統進行檢測了。
readline模塊一般有一個interface類,這個類對應了一些事件和方法。readline還有一些其他的方法,但是最重要的還是interface類,下面我們簡單的講解、學習。
require('readline')
模塊提供了一個接口,用於從可讀流(如 process.stdin
)讀取數據,每次讀取一行。 它可以通過以下方式使用:
const readline = require('readline')
例子,readline
模塊的基本用法:
const readline = require('readline')
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
})
rl.question('你認為nodejs怎么樣?', (answer) => {
//對answer進行處理
console.log(`多謝你的反饋:${answer}`);
rl.close();
})
如下所示:
可以看到: 我們首先引入了readline模塊,然后創建了接口類,接着,我們調用了接口的question方法,第一個參數是一個字符串,第二個是回調函數,參數就是在命令行中輸入的,我們可以對之進行操作。
最后,我們必須使用rl.close()來關閉,否則,node程序不會自動關閉。
Interface類
readline.Interface
類的實例是使用 readline.createInterface()
方法構造的。 每個實例都關聯一個 input
可讀流和一個 output
可寫流。 output
流用於為到達的用戶輸入打印提示,且從 input
流讀取。
'close' 事件
當以下之一發生時,觸發 'close'
事件:
rl.close()
方法被調用,且readline.Interface
實例已撤回對input
流和output
流的控制;input
流接收到'end'
事件;input
流接收到表示結束傳輸的<ctrl>-D
;input
流接收到表示SIGINT
的<ctrl>-C
,且readline.Interface
實例上沒有注冊SIGINT
事件監聽器。
監聽器函數被調用時不傳入任何參數。
當 'close'
事件被觸發時,readline.Interface
實例應當被視為已結束。
'line' 事件
每當 input
流接收到接收行結束符(\n
、\r
或 \r\n
)時觸發 'line'
事件。 通常發生在用戶按下 <Enter>
鍵或 <Return>
鍵。
監聽器函數被調用時會帶上一個包含接收的那一行輸入的字符串。
rl.on('line', (input) => { console.log(`接收到:${input}`); });
即用戶按下了回車時就會觸發line事件,然后,我們就可以使用一個回調函數就收到輸入。
'pause' 事件
當以下之一發生時觸發 'pause'
事件:
監聽器函數被調用時不傳入任何參數。
'resume' 事件
每當 input
流被恢復時觸發 'resume'
事件。
監聽器函數被調用時不傳入任何參數。
例子:
rl.on('resume', () => { console.log('Readline 被恢復。'); });
'SIGCONT' 事件
當一個 Node.js 進程使用 <ctrl>-Z
(也就是 SIGTSTP
)移入后台之后再使用 fg(1p) 移回前台時,觸發 'SIGCONT'
事件。
如果 input
流在 SIGTSTP
請求之前被暫停,則事件不會被觸發。
監聽器函數被調用時不傳入任何參數。
例子:
rl.on('SIGCONT', () => { // `prompt` 會自動恢復流 rl.prompt(); });
rl.close()
rl.close()
方法會關閉 readline.Interface
實例,且撤回對 input
和 output
流的控制。 但被調用時,'close'
事件會被觸發。
rl.promp
rl.prompt()
方法會在 output
流中新的一行寫入 readline.Interface
實例配置后的 prompt
,用於為用戶提供一個可供輸入的新的位置。
當被調用時,如果 input
流已被暫停,則 rl.prompt()
會恢復 input
流。
如果 readline.Interface
被創建時 output
被設為 null
或 undefined
,則提示不會被寫入。
rl.pause()
rl.pause()
方法會暫停 input
流,且稍后需要時可被恢復。
調用 rl.pause()
不會立刻暫停其他事件(包括 'line'
)被 readline.Interface
實例觸發。
rl.question(query, callback)
query
<string> 一個在提示符之前、要寫入output
的敘述或詢問。callback
<Function> 一個回調函數,它會被調用並帶上用戶響應query
的輸入。
rl.question()
方法通過寫入到 output
來展示 query
,並等待用戶提供到 input
的輸入,然后調用 callback
函數並傳入提供的輸入作為第一個參數。
rl.question('你最喜歡的食物是什么? ', (answer) => {
console.log(`你最喜歡的食物是 ${answer}`);
});
rl.resume()
如果 input
流已被暫停,則 rl.resume()
方法會恢復 input
流。
readline.createInterface(options)
簡單的命令行界面
const readline = require('readline'); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, prompt: '請輸入> ' }); rl.prompt(); rl.on('line', (line) => { switch (line.trim()) { case 'hello': console.log('world!'); break; default: console.log(`你輸入的是:'${line.trim()}'`); break; } rl.prompt(); }).on('close', () => { console.log('再見!'); process.exit(0); });
例子:逐行地讀取文件流
const readline = require('readline'); const fs = require('fs'); const rl = readline.createInterface({ input: fs.createReadStream('sample.txt') }); rl.on('line', (line) => { console.log(`文件的單行內容:${line}`); });