Leetcode ซูโดกุที่ถูกต้อง
ลิงค์ที่นี่
ฉันจะรวมโซลูชันใน Python และ C ++ และคุณสามารถตรวจสอบได้ ฉันสนใจที่จะตรวจสอบโค้ด C ++ ซึ่งเป็นสิ่งที่ฉันเพิ่งเริ่มเรียนรู้ ผู้ที่ไม่ทราบ C ++ สามารถตรวจสอบโค้ด Python ได้ โซลูชันทั้งสองใช้ตรรกะที่คล้ายกันดังนั้นการตรวจสอบจะนำไปใช้กับ
คำชี้แจงปัญหา
ตรวจสอบว่าบอร์ดซูโดกุ 9 x 9 ถูกต้องหรือไม่ เฉพาะเซลล์ที่เติมเท่านั้นที่ต้องได้รับการตรวจสอบตามกฎต่อไปนี้:
- แต่ละแถวต้องมีตัวเลข 1-9 โดยไม่มีการซ้ำ แต่ละคอลัมน์
- ต้องมีตัวเลข 1-9 โดยไม่มีการซ้ำ แต่ละเก้า 3 x
- 3 ช่องย่อยของตารางต้องมีตัวเลข 1-9 โดยไม่มีการทำซ้ำ
บันทึก:
บอร์ด Sudoku (เติมบางส่วน) อาจใช้ได้ แต่ไม่จำเป็นต้องแก้ได้ เฉพาะเซลล์ที่เติมเท่านั้นที่ต้องได้รับการตรวจสอบตามกฎที่กล่าวถึง
ตัวอย่างที่ 1:
Input: board =
[["5","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
Output: true
ตัวอย่างที่ 2:
Input: board =
[["8","3",".",".","7",".",".",".","."]
,["6",".",".","1","9","5",".",".","."]
,[".","9","8",".",".",".",".","6","."]
,["8",".",".",".","6",".",".",".","3"]
,["4",".",".","8",".","3",".",".","1"]
,["7",".",".",".","2",".",".",".","6"]
,[".","6",".",".",".",".","2","8","."]
,[".",".",".","4","1","9",".",".","5"]
,[".",".",".",".","8",".",".","7","9"]]
Output: false
Explanation: Same as Example 1, except with the 5 in the top left corner being modified to 8. Since there are two 8's in the top left 3x3 sub-box, it is invalid.
valid_sudoku.py
def is_valid(board, empty_value='.', b_size=3):
seen = set()
size = b_size * b_size
for row in range(size):
for col in range(size):
if (value := board[row][col]) == empty_value:
continue
r = f'0{row}{value}'
c = f'1{col}{value}'
b = f'2{row // b_size}{col // b_size}{value}'
if r in seen or c in seen or b in seen:
return False
seen.update({r, c, b})
return True
if __name__ == '__main__':
g = [
["5", "3", ".", ".", "7", "5", ".", ".", "."],
["6", ".", ".", "1", "9", "5", ".", ".", "."],
[".", "9", "8", ".", ".", ".", ".", "6", "."],
["8", ".", ".", ".", "6", ".", ".", ".", "3"],
["4", ".", ".", "8", ".", "3", ".", ".", "1"],
["7", ".", ".", ".", "2", ".", ".", ".", "6"],
[".", "6", ".", ".", ".", ".", "2", "8", "."],
[".", ".", ".", "4", "1", "9", ".", ".", "5"],
[".", ".", ".", ".", "8", ".", ".", "7", "9"],
]
print(is_valid(g))
สถิติ:
Runtime: 92 ms, faster than 81.70% of Python3 online submissions for Valid Sudoku.
Memory Usage: 14.1 MB, less than 73.95% of Python3 online submissions for Valid Sudoku.
นี่เป็นทางเลือกอื่นโดยใช้ numpy ซึ่งสั้นกว่าและอ่านง่ายกว่า แต่ช้ากว่า:
import numpy as np
def is_valid(board, size=3, empty_value='.'):
board = np.array(board)
blocks = board.reshape(4 * [size]).transpose(0, 2, 1, 3).reshape(2 * [size * size])
for grid in [board, board.T, blocks]:
for line in grid:
non_empty = line[line != empty_value]
if not len(non_empty) == len(set(non_empty)):
return False
return True
สถิติ:
Runtime: 172 ms, faster than 5.19% of Python3 online submissions for Valid Sudoku.
Memory Usage: 30.2 MB, less than 11.10% of Python3 online submissions for Valid Sudoku.
valid_sudoku.h
#ifndef LEETCODE_VALID_SUDOKU_H
#define LEETCODE_VALID_SUDOKU_H
#include <string_view>
#include <unordered_set>
bool sudoku_check_update(const size_t &row, const size_t &col, const char &value,
const int &block_size,
std::unordered_set<std::string_view> &seen);
bool sudoku_check(const std::vector<std::vector<char>> &board,
const char &empty_value = '.');
void test1();
#endif //LEETCODE_VALID_SUDOKU_H
valid_sudoku.cpp
#include <iostream>
#include <vector>
#include <string_view>
#include <cmath>
#include <unordered_set>
bool sudoku_check_update(const size_t &row, const size_t &col, const char &value,
const int &block_size,
std::unordered_set<std::string_view> &seen) {
std::string_view r, c, b;
r = "0-" + std::to_string(row) + value;
c = "1-" + std::to_string(col) + value;
b = "2-" + std::to_string(row / block_size) + std::to_string(col / block_size) +
value;
for (const auto &seen_id: {r, c, b}) {
if (seen.find(seen_id) != seen.end())
return false;
seen.insert(seen_id);
}
return true;
}
bool sudoku_check(const std::vector<std::vector<char>> &board,
const char &empty_value = '.') {
std::unordered_set<std::string_view> seen;
const auto row_size = board.size();
const int block_size = std::sqrt(row_size);
for (size_t row = 0; row < row_size; ++row) {
for (size_t col = 0; col < row_size; ++col) {
auto value = board[row][col];
if (value == empty_value)
continue;
if (!sudoku_check_update(row, col, value, block_size, seen))
return false;
}
}
return true;
}
void test1() {
std::vector<std::vector<char>> v = {
{'5', '3', '.', '.', '7', '.', '.', '.', '.'},
{'6', '.', '.', '1', '9', '5', '.', '.', '.'},
{'.', '9', '8', '.', '.', '.', '.', '6', '.'},
{'8', '.', '.', '.', '6', '.', '.', '.', '3'},
{'4', '.', '.', '8', '.', '3', '.', '.', '1'},
{'7', '.', '.', '.', '2', '.', '.', '.', '6'},
{'.', '6', '.', '.', '.', '.', '2', '8', '.'},
{'.', '.', '.', '4', '1', '9', '.', '.', '5'},
{'.', '.', '.', '.', '8', '.', '.', '7', '9'}
};
std::cout << sudoku_check(v);
}
สถิติ:
Runtime: 48 ms, faster than 17.98% of C++ online submissions for Valid Sudoku.
Memory Usage: 20.4 MB, less than 22.55% of C++ online submissions for Valid Sudoku.
คำตอบ
คำแนะนำบางประการเกี่ยวกับวิธีที่คุณจะสามารถปรับปรุงโค้ดของคุณได้
เวอร์ชัน C ++
ใช้#includes ที่จำเป็นทั้งหมด
ชนิดstd::vector<std::vector<char>>ถูกใช้ในคำจำกัดความของsudoku_check()ในไฟล์ส่วนหัว แต่#include <vector>ไม่มีอยู่ในรายการรวมที่นั่น
ย่อส่วนอินเทอร์เฟซ
.hไฟล์คือการประกาศของอินเตอร์เฟซซอฟแวร์ของคุณ .cppคือการดำเนินงานของอินเตอร์เฟซที่ เป็นการออกแบบที่ดีในการย่อส่วนอินเทอร์เฟซให้เหลือเพียงที่โปรแกรมภายนอกต้องการ สำหรับเหตุผลที่ฉันจะลบsudoku_check_update()และtest1()ฟังก์ชั่นและใช้เพียงนี้:
#ifndef LEETCODE_VALID_SUDOKU_H
#define LEETCODE_VALID_SUDOKU_H
#include <vector>
bool sudoku_check(const std::vector<std::vector<char>> &board,
const char &empty_value = '.');
#endif //LEETCODE_VALID_SUDOKU_H
การนำไปใช้งานควรมีส่วนหัวของอินเทอร์เฟซ
เนื่องจากชื่อของส่วนนี้ระบุการใช้งานควรมีส่วนหัวของอินเทอร์เฟซ สิ่งนี้ทำให้มั่นใจได้ว่าอินเทอร์เฟซและการใช้งานตรงกันและขจัดข้อผิดพลาด หากเราทำเช่นนั้นในกรณีนี้เราจะเห็นว่าค่าเริ่มต้นสำหรับempty_valueถูกประกาศสองครั้ง ควรประกาศเพียงครั้งเดียวในไฟล์ส่วนหัว
สร้างฟังก์ชันท้องถิ่น static
ด้วยอินเทอร์เฟซที่เล็กกว่าดังที่ได้รับการสนับสนุนข้างต้นsudoku_check_updateฟังก์ชันนี้จะกลายเป็นรายละเอียดการใช้งานที่ใช้ภายใน.cppไฟล์เท่านั้น ด้วยเหตุนี้จึงควรทำstaticเพื่อให้คอมไพเลอร์รู้ว่าการอินไลน์ฟังก์ชันนั้นปลอดภัย
คีย์เวิร์ดstaticเมื่อใช้กับการประกาศฟังก์ชันระบุว่าการเชื่อมโยงเป็นแบบภายใน กล่าวอีกนัยหนึ่งก็หมายความว่าไม่มีสิ่งใดนอกไฟล์นั้นที่สามารถเข้าถึงฟังก์ชันได้ สิ่งนี้มีประโยชน์สำหรับคอมไพลเลอร์ที่จะต้องทราบเนื่องจากตัวอย่างเช่นหากstaticฟังก์ชันถูกใช้เพียงครั้งเดียวและ / หรือมีขนาดเล็กคอมไพเลอร์จะมีตัวเลือกในการใส่โค้ดแบบอินไลน์ นั่นคือแทนที่จะเป็นภาษาแอสเซมบลีตามปกติcall... retคำแนะนำในการข้ามไปยังรูทีนย่อยและกลับมาจากมันคอมไพลเลอร์สามารถใส่โค้ดสำหรับฟังก์ชันได้โดยตรงที่ตำแหน่งนั้นช่วยประหยัดค่าใช้จ่ายในการคำนวณของคำสั่งเหล่านั้นและช่วยให้มั่นใจในแคช การคาดคะเนถูกต้อง (เนื่องจากโดยปกติแคชจะใช้ประโยชน์จากตำแหน่งที่ตั้งของการอ้างอิง )
อ่านเพิ่มเติมเกี่ยวกับตัวระบุคลาสพื้นที่จัดเก็บเพื่อทำความเข้าใจสิ่งที่staticทำในบริบทอื่น ๆ และตัวระบุการประกาศโดยทั่วไปสำหรับคำอธิบายconstexprและอื่น ๆ
แก้ไขข้อบกพร่อง!
รหัสนี้ใช้string_viewอย่างไม่เหมาะสม A std::string_viewคือตัวชี้ไปยังสตริงที่มีอยู่ std::string_viewแต่สายของคุณจะประกอบด้วยและลบแบบไดนามิกดังนั้นนี่คือการใช้งานที่ไม่ถูกต้อง หากคุณแทนที่อินสแตนซ์ทั้งหมดstring_viewด้วยstringโปรแกรมจะทำงานได้
ปัญหาหน่วยความจำเช่นนี้และข้อผิดพลาดพร้อมกันเป็นปัญหาที่ยากที่สุดสำหรับโปรแกรมเมอร์ในการตรวจจับและแก้ไข เมื่อคุณได้รับประสบการณ์มากขึ้นคุณจะพบว่าความสามารถในการมองเห็นปัญหาเหล่านี้และหลีกเลี่ยงปัญหาเหล่านี้จะเกิดขึ้นในทันที มีหลายวิธีในการค้นหาข้อผิดพลาดดังกล่าว ดูคลาสง่ายๆในการตรวจจับการรั่วไหลสำหรับบางคน
เขียนฟังก์ชันการทดสอบที่ดีขึ้น
จุดบกพร่องที่กล่าวถึงข้างต้นสามารถค้นพบได้อย่างง่ายดายโดยการเรียกใช้ฟังก์ชันหลาย ๆ ครั้งด้วยอินพุตที่แตกต่างกัน บางทีคุณอาจมีฟังก์ชั่นการทดสอบที่กว้างขวางกว่านี้อยู่แล้ว แต่ถ้าไม่เป็นเช่นนั้นฉันขอแนะนำให้สร้างและนำไปใช้
ใช้โครงสร้างข้อมูลที่มีประสิทธิภาพ
หากเป้าหมายของรหัสนี้มีประสิทธิภาพทั้งในแง่ของเวลาทำงานและหน่วยความจำก็มีการปรับปรุงมากมายที่สามารถทำได้ ประการแรกโครงสร้างข้อมูลstd::unordered_set<std::string_view>ไม่เหมาะสม เมื่อใดก็ตามที่เรากำลังดำเนินการเพิ่มประสิทธิภาพการวัดผลก็มีประโยชน์ ดังนั้นผมจึงเขียนโปรแกรมการทดสอบที่ง่ายมากขึ้นอยู่กับฉันเทมเพลตนาฬิกาจับเวลา ที่นี่:
#include "valid_sudoku.h"
#include "stopwatch.h"
#include <iostream>
#include <vector>
#include <string>
int main(int argc, char* argv[]) {
std::vector<std::vector<char>> v = {
{'5', '3', '.', '.', '7', '.', '.', '.', '.'},
{'6', '.', '.', '1', '9', '5', '.', '.', '.'},
{'.', '9', '8', '.', '.', '.', '.', '6', '.'},
{'8', '.', '.', '.', '6', '.', '.', '.', '3'},
{'4', '.', '.', '8', '.', '3', '.', '.', '1'},
{'7', '.', '.', '.', '2', '.', '.', '.', '6'},
{'.', '6', '.', '.', '.', '.', '2', '8', '.'},
{'.', '.', '.', '4', '1', '9', '.', '.', '5'},
{'.', '.', '.', '.', '8', '.', '.', '7', '9'}
};
if (argc != 2) {
std::cout << "Usage: " << argv[0] << " num_trials\n";
return 1;
}
auto iterations = std::stoul(argv[1]);
Stopwatch<> timer{};
bool valid{true};
for (auto i{iterations}; i; --i) {
valid &= sudoku_check(v);
}
auto elapsed{timer.stop()};
if (!valid) {
std::cout << "The program failed!\n";
return 2;
}
std::cout << iterations << " trials took " << elapsed << " microseconds\n"
" for an average of " << elapsed/iterations << " microseconds/trial\n";
}
เมื่อฉันรันสิ่งนี้บนเครื่องของฉันด้วยการทดลอง 1,000,000 ครั้ง (โดยที่ข้อบกพร่องที่ระบุไว้ข้างต้นได้รับการแก้ไขตามที่อธิบายไว้) นี่คือผลลัพธ์ที่ฉันได้รับ:
การทดลอง 1000000 ครั้งใช้เวลา 1.44351e + 07 ไมโครวินาทีโดยเฉลี่ย 14.4351 ไมโครวินาที / การทดลอง
ทีนี้ลองนึกถึงโครงสร้างข้อมูลที่มีประสิทธิภาพมากขึ้น แทนที่จะเป็นunordered_setเราอาจใช้ชุดของอาร์เรย์คงที่ มีเก้าแถวเก้าคอลัมน์และเก้าตารางย่อย แต่ละรายการมีตัวเลขหรือไม่มี สำหรับฉันนั่นแสดงให้เห็นว่าเราสามารถใช้วัตถุเช่นนี้:
using SeenType = std::array<std::array<std::array<bool, 9>, 9>, 3>;
ซึ่งประกอบด้วย 3 ประเภท (แถวคอลัมน์จัตุรัสย่อย) และภายในแต่ละชุดมี 9 คอลเล็กชัน 9 บิต หนึ่งบิตสำหรับแต่ละหมายเลข ลองเขียนฟังก์ชันใหม่เพื่อใช้สิ่งนี้:
static bool sudoku_check_update(std::size_t row, std::size_t col,
char value, SeenType &seen) {
static constexpr std::size_t block_size{3};
static_assert(block_size * block_size == row_size, "block_size must be the square root of row_size");
const std::size_t block = col / block_size + block_size * (row / block_size);
std::size_t dim{0};
value -= '1'; // adjust from digits '1'-'9' to indices 0-8.
for (const auto &seen_id: {row, col, block}) {
if (seen[dim][seen_id][value])
return false;
seen[dim][seen_id][value] = true;
++dim;
}
return true;
}
ตอนนี้เรียกใช้โปรแกรมอีกครั้งด้วยการทดลองใช้หนึ่งล้านครั้งเหมือนเดิม:
การทดลอง 1000000 ครั้งใช้เวลา 562153 ไมโครวินาทีโดยเฉลี่ย 0.562153 ไมโครวินาที / การทดลอง
ดังนั้นการเปลี่ยนแปลงที่หนึ่งทำสิ่งที่25x ได้เร็วขึ้น เรายังสามารถใช้ความจริงที่ว่ามิติข้อมูลนั้นใช้std::array<std::array<char, 9>, 9>แทนเวกเตอร์และใช้constexprสำหรับมิติเหล่านั้นได้ เมื่อทำการเปลี่ยนแปลงเช่นกันเราจะได้รับสิ่งนี้:
การทดลอง 1000000 ครั้งใช้เวลา 160808 ไมโครวินาทีโดยเฉลี่ย 0.160808 ไมโครวินาที / การทดลอง
ตอนนี้เร็วขึ้น 90เท่า
ต้องการการ{}เริ่มต้นสไตล์
คุณอาจสังเกตว่าโค้ดที่ฉันเขียนมีแนวโน้มที่จะใช้{}- สไตล์การเริ่มต้น มีสาเหตุหลายประการรวมถึงข้อเท็จจริงที่ว่าเมื่อคุณเห็นมันเป็นการเริ่มต้นเสมอและไม่สามารถเข้าใจผิดว่าเป็นการเรียกใช้ฟังก์ชัน ดูES.23สำหรับรายละเอียดเพิ่มเติม
ส่งผ่านค่ามากกว่าการอ้างอิงสำหรับชนิดข้อมูลสั้น ๆ
แทนที่จะผ่านไปconst size_t &colหรือconst char& valueโดยทั่วไปแล้วจะดีกว่าที่จะส่งผ่านค่าเหล่านั้น สิ่งนี้มักเป็นประโยชน์เนื่องจากตัวชี้มีแนวโน้มที่จะยาวกว่าสิ่งที่ชี้ไปและเนื่องจากช่วยให้สามารถกำจัดการค้นหาทิศทางและหน่วยความจำได้
ย้ายการคำนวณจากรันไทม์ไปยังคอมไพล์เวลาที่ใช้งานได้จริง
อาจใช้เวลาไม่มาก แต่บรรทัดนี้ไม่เร็วเท่าที่ควร:
const int block_size = std::sqrt(row_size);
สิ่งนี้คือการแปลงrow_sizeเป็น a doubleเรียกใช้sqrtฟังก์ชันจุดลอยตัวและแปลงdoubleกลับเป็นintไฟล์. ในทางตรงกันข้ามเราสามารถเขียนสิ่งนี้ได้:
constexpr std::size_t block_size{3};
ตอนนี้ใช้เวลาไม่นานเลยในรันไทม์เนื่องจากทราบค่าในเวลาคอมไพล์ นอกจากนี้ยังช่วยลดการต้องผ่านค่าและดังที่กล่าวมาข้างต้นคำจำกัดความของมันสามารถวางไว้ที่เดียวที่จำเป็นจริงซึ่งอยู่ในsudoku_check_updateฟังก์ชัน
โดยทั่วไปเราชอบที่จะย้ายสิ่งต่างๆจากรันไทม์เพื่อรวบรวมเวลาด้วยเหตุผลสามประการ:
- โดยทั่วไปโปรแกรมจะทำงานมากกว่าที่คอมไพล์ดังนั้นเราจึงปรับให้เหมาะสมกับเหตุการณ์ที่เกิดขึ้นบ่อยกว่า
- ยิ่งเราตรวจพบจุดบกพร่องเร็วเท่าไหร่ก็ยิ่งถูกและแก้ไขได้ง่ายขึ้นเท่านั้น
- มีแนวโน้มที่จะทำให้ซอฟต์แวร์มีขนาดเล็กลงและภายในง่ายขึ้นซึ่งจะช่วยเพิ่มความเร็วในการโหลดประสิทธิภาพแคชและซอฟต์แวร์ที่เรียบง่ายมีแนวโน้มที่จะปรับปรุงคุณภาพ
เวอร์ชัน Python
หลีกเลี่ยงcontinueโดยการปรับโครงสร้างลูป
ไม่มีอะไรที่ยิ่งผิดปกติกับการใช้งานของผู้ประกอบการวอลรัส continueแต่ดูเหมือนว่าจะมีเหตุผลเพียงเล็กน้อยที่จะไม่กลับความรู้สึกของการเปรียบเทียบและเพียงแค่ขั้นตอนการปรับปรุงมากกว่าการใช้ ไม่มีผลต่อประสิทธิภาพการทำงาน แต่ช่วยให้ผู้อ่านโค้ดเข้าใจกระบวนการทำงานของโปรแกรม ฉันมักจะใส่ต้น "bailout" ข้อต้นในการทำงานได้อย่างรวดเร็วปฏิเสธเงื่อนไขที่ไม่ถูกต้อง แต่หลีกเลี่ยงcontinueในลูป; ท้ายที่สุดมันเป็นคำถามเกี่ยวกับความสามารถในการอ่านและรูปแบบใน C ++ หรือ Python
ใช้โครงสร้างข้อมูลที่มีประสิทธิภาพมากขึ้น
สิ่งที่เป็นจริงใน C ++ ก็ใช้ได้ใน Python เราสามารถใช้แนวคิดเดียวกันและเร่งความเร็วโค้ดโดยปัจจัย 6:
def is_valid(board, empty_value='.', b_size=3):
size = b_size * b_size
seen = [[(size * [False]) for _ in range(size)] for _ in range(3)]
for row in range(size):
for col in range(size):
if (value := board[row][col]) != empty_value:
block = col // b_size + b_size * (row // b_size)
dim = 0
value = int(value) - 1
for seen_id in [row, col, block]:
if seen[dim][seen_id][value]:
return False
seen[dim][seen_id][value] = True
dim += 1
return True
ไมเนอร์ (และ Python) แต่โดยส่วนตัวแล้วฉันพบว่าสิ่งนี้สับสนเล็กน้อย:
if (value := board[row][col]) == empty_value:
continue
r = f'0{row}{value}'
c = f'1{col}{value}'
b = f'2{row // b_size}{col // b_size}{value}'
คุณกำลังใช้นิพจน์การกำหนดเพื่อกำหนดค่า แต่จะใช้ในกรณีเท็จเท่านั้น ฉันคิดว่าสิ่งนี้จะสะอาดกว่ามากโดยใช้คำสั่งมอบหมายแบบธรรมดา:
value = board[row][col]
if value == empty_value:
continue
r = f'0{row}{value}'
c = f'1{col}{value}'
b = f'2{row // b_size}{col // b_size}{value}'
ฉันไม่คิดว่าบรรทัดที่บันทึกไว้จะคุ้มค่ากับการสร้างตัวแปร
C ++
ง่ายกว่าและอาจเร็วกว่าที่จะส่งผ่านประเภทข้อมูลธรรมดาขนาดเล็กเช่นsize_tและcharตามค่าไม่ใช่โดยการอ้างอิง ดังนั้นเราควรมี:
bool sudoku_check_update(size_t row, size_t col, char value, int block_size,
std::unordered_set<std::string_view> &seen)
bool sudoku_check(const std::vector<std::vector<char>> &board,
char empty_value = '.')
ที่สำคัญกว่า: std::string_view ไม่สามารถใช้สำหรับจัดเก็บสตริง ไม่ได้เป็นเจ้าของสตริง แต่เป็นเพียงตัวชี้และขนาด
ในการทำสิ่งนี้:
std::string_view r = "0-" + std::to_string(row) + value;
... เราสร้างชั่วคราวstd::stringแล้วกำหนดให้กับstring_view. อย่างไรก็ตามสตริงชั่วคราวจะอยู่นอกขอบเขตที่ท้ายบรรทัดนี้!
มันผ่านไปแล้ว สตริงนี้ไม่มาก มันหยุดที่จะเป็น หมดอายุแล้วไปพบผู้ผลิต นี่คือสตริงตอนปลาย มันแข็ง ชีวิตที่ไม่ได้อยู่ในความสงบ ถ้าเราไม่ตอกมันลงไป
std::string_viewมันจะเป็นการผลักดอกเดซี่ขึ้น มันพังม่านลงและเข้าร่วมกับนักร้องประสานเสียงที่มองไม่เห็น นี่คือสตริงเก่า
ในคำอื่น ๆ string_viewก็ไม่ได้กำหนดพฤติกรรมที่จะลองและการใช้งานที่ ดังนั้นr, cและbจำเป็นที่จะต้องstd::strings ตัวเอง และควรจะเป็นseenstd::unordered_set<std::string>
เรื่อง std::string_view:
std::string_viewชี้ไปที่ช่วงของอักขระในหน่วยความจำ อักขระเหล่านี้สามารถเก็บไว้ใน a std::stringในstd::arraya std::vectorหรือใน string-literal
ด้วยการใช้std::string_viewเราจะได้รับอินเทอร์เฟซเดียวกัน (การค้นหาการเปรียบเทียบการสร้างสตริงย่อย) โดยไม่คำนึงถึงสิ่งที่จัดเก็บข้อมูลพื้นฐานนั้น ดังนั้นจึงมีประโยชน์ในฐานะภาษากลางระหว่างประเภทเหล่านี้
เนื่องจากstd::string_viewไม่ได้เป็นเจ้าของอักขระจึงไม่มีการจัดสรรหน่วยความจำหรือคัดลอกตัวเอง นี้จะทำให้มันมีประโยชน์สำหรับสิ่งที่ต้องการแยกไฟล์ข้อความยาว - เราสามารถค้นหาและเปรียบเทียบในสตริงโดยไม่ต้องทำการคัดลอกที่std::stringจะทำ
ข้อเสียคือเราต้องตรวจสอบให้แน่ใจว่าอายุการใช้งานของสตริงจริงในหน่วยความจำนั้นยาวนานกว่าของstring_view.