Huawei機試系列(2)
阿新 • • 發佈:2020-08-16
從單向連結串列中刪除指定值的節點
問題描述詳見 從單向連結串列中刪除指定值的節點
- 自己實現一個單鏈表,插入和刪除
- 注意頭節點,輸出格式
#include <iostream> using namespace std; struct Node { int elem; Node* next; Node(int e) :elem(e), next(nullptr) {} }; class linkList { private: Node* head; public: linkList(int e) :head(new Node(e)) {} void insert(int val, int pos) { Node* it = head; while (it->elem != pos) { //找到插入節點的前一個位置 if (it->next) it = it->next; else return; } Node* node = new Node(val); node->next = it->next; it->next = node; } void remove(int pos) { Node* it, * temp; if (head->elem == pos) { temp = head; head = head->next; delete temp; } it = head; while (it->next && it->next->elem != pos) it = it->next; if (it->next) { temp = it->next; it->next = it->next->next; delete temp; } } void printList() { Node* it = head; while (it != nullptr) { cout << it->elem << ' '; it = it->next; } cout << endl; } }; int main() { int nodeNum, headNode, v, p, delNode; while (cin >> nodeNum >> headNode) { linkList* myList = new linkList(headNode); while (nodeNum != 1) { cin >> v >> p; myList->insert(v, p); --nodeNum; } cin >> delNode; myList->remove(delNode); myList->printList(); } }
說明
-
其實測試樣例不會在未定義的節點之後插入資料,也不會刪除沒有定義的節點,所以其實可以簡化一部分程式碼
-
本地IDE測試是沒有問題的,但是牛客網的測試環境輸出會異常。本地除錯的輸出結果和可以AC的程式碼在測試樣例上結果一致,但牛客網環境下會把輸入先輸出在輸出結果。
使用STL的簡潔版本
#include<iostream> #include<algorithm> #include<list> int main() { int nodeNum, headVal, delNodeVal, pos, val; std::cin >> nodeNum >> headVal; std::list<int> myList; myList.emplace_back(headVal); for (int i = 1; i < nodeNum; ++i) { std::cin >> val >> pos; myList.insert(++find(myList.begin(), myList.end(), pos), val); } std::cin >> delNodeVal; myList.erase(find(myList.begin(), myList.end(), delNodeVal)); for (auto elem : myList) std::cout << elem << " "; std::cout << std::endl; }
破案
需要處理多組測試資料,也就是說輸入都要用while()迴圈,Bcompare對了半天找bug,emmm
輸出單向連結串列中倒數第k個結點
問題描述詳見輸出單向連結串列中倒數第k個結點
雙指標的問題,單鏈表傳送門。這個issue有個需要注意的地方就是,最後一個節點是尾指標,也即當k允許取零,這時候取出的元素值是無效值,若不處理這種情況會提示越界訪問。
#include<iostream> struct Node { int elem; Node* next; Node(int e) :elem(e), next(nullptr) {} }; class linkList { private: Node* head; //elem儲存連結串列元素個數 public: linkList() { Node* node = new Node(0); head = node; } void insert(int num) { Node* it = head; int val; while (num--) { std::cin >> val; Node* node = new Node(val); it->next = node; it = it->next; ++head->elem; } } Node* reverseK(int k) { if (k > head->elem) return nullptr; else { Node* p = head; Node* q = head; while (k--) q = q->next; while (q) { p = p->next; q = q->next; } std::cout << p->elem << std::endl; return p; } } }; int main() { int nodeNum, k; while (std::cin >> nodeNum) { linkList myList; myList.insert(nodeNum); std::cin >> k; if (k == 0) std::cout << 0 << std::endl; else myList.reverseK(k); } }
密碼擷取
問題描述詳見字串運用-密碼擷取
遞迴
當字串很短時,可以考慮遞迴,但是當字串很長的時候效率很低。
//擷取最長對稱串
#include<iostream>
#include<string>
#include<algorithm>
auto getMax = [](int a, int b, int c) {
return std::max(std::max(a, b), std::max(a, c));
};
bool check(std::string str)
{
int len = str.length();
for (int i = 0; i < len / 2; i++)
if (str[i] != str[len - 1 - i])
return false;
return true;
}
int f(std::string str) {
if (check(str))
return str.length();
return getMax(f(str.substr(0, str.length() - 1)), f(str.substr(1, str.length())), f(str.substr(1, str.length() - 1)));
}
int main()
{
std::string str;
while (std::cin >> str)
std::cout << f(str) << std::endl;
}
注:
遞迴的複雜度可以通過儲存中間結果或改變遞迴方向等技巧來降低,這裡挖個坑~~日後來填
動態規劃
這個題目可以轉化成求最長公共子串的問題,將原字串逆轉之後,求最長公共子串
#include <iostream>
#include<string>
#include<algorithm>
using namespace std;
int main() {
string x,y;
while (cin >> x) {
y.resize(x.size());
reverse_copy(x.begin(), x.end(), y.begin());
int maxLen = 0;
int** dp = new int* [x.length() + 1];
for (unsigned int i = 0; i <= x.length(); ++i)
dp[i] = new int[y.length() + 1];
for (unsigned int i = 0; i <= x.length(); ++i)
for (unsigned int j = 0; j <= y.length(); ++j) {
if (i == 0 || j == 0 || x[i - 1] != y[j - 1])
dp[i][j] = 0;
else
{
dp[i][j] = dp[i - 1][j - 1] + 1;
maxLen = max(maxLen, dp[i][j]);
}
}
cout << maxLen << endl;
for (unsigned int i = 0; i < y.length(); ++i) //二維陣列的釋放
delete[]dp[i];
delete[] dp;
}
}
補充
本題可以遍歷一遍,計算每一個位置為中心時奇數和偶數長度迴文串的長度,輸出最大值
#include <iostream>
#include<algorithm>
using namespace std;
int decrypt(string passwd)
{
int maxLen = 0;
for (int i = 1; i < passwd.length(); ++i)
{
int low, high;
low = i - 1, high = i;
while (low >= 0 && high < passwd.length() && passwd[low] == passwd[high]) {
low--;
high++;
}
maxLen = max(maxLen, high - low - 1);
low = i - 1; high = i + 1;
while (low >= 0 && high < passwd.length() && passwd[low] == passwd[high]) {
low--;
high++;
}
maxLen = max(maxLen, high - low - 1);
}
return maxLen;
}
int main() {
string str;
while (cin >> str)
cout << decrypt(str) << endl;
}
簡單密碼
問題描述詳見簡單密碼破解
注意大寫字母類似‘’迴圈移位’‘,取餘
#include <iostream>
using namespace std;
string decrypt(string str)
{
for (auto& ch : str)
{
if (ch >= 'A' && ch <= 'Z')
ch = static_cast<char>(static_cast<int>((ch - 'A' + 1) % 26) + 'a');
else if (ch >= 'a' && ch <= 'c')
ch = '2';
else if (ch >= 'd' && ch <= 'f')
ch = '3';
else if (ch >= 'g' && ch <= 'i')
ch = '4';
else if (ch >= 'j' && ch <= 'l')
ch = '5';
else if (ch >= 'm' && ch <= 'o')
ch = '6';
else if (ch >= 'p' && ch <= 's')
ch = '7';
else if (ch >= 't' && ch <= 'v')
ch = '8';
else if (ch >= 'w' && ch <= 'z')
ch = '9';
}
return str;
}
int main() {
string passwd;
while(cin >> passwd)
cout << decrypt(passwd) << endl;
}