Add ru version (#1865)

* Add Russian docs site baseline

* Add Russian localized codebase

* Polish Russian code wording

* Update ru code translation.

* Update code translation and chapter covers.

* Fix pythontutor extraction.

* Add README and landing page.

* placeholder of profiles

* Use figures of English version

* Remove chapter paperbook
This commit is contained in:
Yudong Jin
2026-03-28 04:24:07 +08:00
committed by GitHub
parent 2ca570cc33
commit 772183705e
1958 changed files with 108186 additions and 0 deletions
@@ -0,0 +1,76 @@
/*
* File: n_queens.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
/* Алгоритм бэктрекинга: n ферзей */
fn backtrack(
row: usize,
n: usize,
state: &mut Vec<Vec<String>>,
res: &mut Vec<Vec<Vec<String>>>,
cols: &mut [bool],
diags1: &mut [bool],
diags2: &mut [bool],
) {
// Когда все строки уже обработаны, записать решение
if row == n {
res.push(state.clone());
return;
}
// Обойти все столбцы
for col in 0..n {
// Вычислить главную и побочную диагонали, соответствующие этой клетке
let diag1 = row + n - 1 - col;
let diag2 = row + col;
// Отсечение: в столбце, главной диагонали и побочной диагонали этой клетки не должно быть ферзей
if !cols[col] && !diags1[diag1] && !diags2[diag2] {
// Попытка: поставить ферзя в эту клетку
state[row][col] = "Q".into();
(cols[col], diags1[diag1], diags2[diag2]) = (true, true, true);
// Перейти к размещению следующей строки
backtrack(row + 1, n, state, res, cols, diags1, diags2);
// Откат: восстановить эту клетку как пустую
state[row][col] = "#".into();
(cols[col], diags1[diag1], diags2[diag2]) = (false, false, false);
}
}
}
/* Решить задачу о n ферзях */
fn n_queens(n: usize) -> Vec<Vec<Vec<String>>> {
// Инициализировать доску размера n*n, где 'Q' обозначает ферзя, а '#' — пустую клетку
let mut state: Vec<Vec<String>> = vec![vec!["#".to_string(); n]; n];
let mut cols = vec![false; n]; // Отмечать, есть ли ферзь в столбце
let mut diags1 = vec![false; 2 * n - 1]; // Отмечать наличие ферзя на главной диагонали
let mut diags2 = vec![false; 2 * n - 1]; // Отмечать наличие ферзя на побочной диагонали
let mut res: Vec<Vec<Vec<String>>> = Vec::new();
backtrack(
0,
n,
&mut state,
&mut res,
&mut cols,
&mut diags1,
&mut diags2,
);
res
}
/* Driver Code */
pub fn main() {
let n: usize = 4;
let res = n_queens(n);
println!("Размер входной доски = {n}");
println!("Количество способов расстановки ферзей: {}", res.len());
for state in res.iter() {
println!("--------------------");
for row in state.iter() {
println!("{:?}", row);
}
}
}
@@ -0,0 +1,46 @@
/*
* File: permutations_i.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
/* Алгоритм бэктрекинга: все перестановки I */
fn backtrack(mut state: Vec<i32>, choices: &[i32], selected: &mut [bool], res: &mut Vec<Vec<i32>>) {
// Когда длина состояния равна числу элементов, записать решение
if state.len() == choices.len() {
res.push(state);
return;
}
// Перебор всех вариантов выбора
for i in 0..choices.len() {
let choice = choices[i];
// Отсечение: нельзя выбирать один и тот же элемент повторно
if !selected[i] {
// Попытка: сделать выбор и обновить состояние
selected[i] = true;
state.push(choice);
// Перейти к следующему выбору
backtrack(state.clone(), choices, selected, res);
// Откат: отменить выбор и восстановить предыдущее состояние
selected[i] = false;
state.pop();
}
}
}
/* Все перестановки I */
fn permutations_i(nums: &mut [i32]) -> Vec<Vec<i32>> {
let mut res = Vec::new(); // Состояние (подмножество)
backtrack(Vec::new(), nums, &mut vec![false; nums.len()], &mut res);
res
}
/* Driver Code */
pub fn main() {
let mut nums = [1, 2, 3];
let res = permutations_i(&mut nums);
println!("Входной массив nums = {:?}", &nums);
println!("Все перестановки res = {:?}", &res);
}
@@ -0,0 +1,50 @@
/*
* File: permutations_ii.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
use std::collections::HashSet;
/* Алгоритм бэктрекинга: все перестановки II */
fn backtrack(mut state: Vec<i32>, choices: &[i32], selected: &mut [bool], res: &mut Vec<Vec<i32>>) {
// Когда длина состояния равна числу элементов, записать решение
if state.len() == choices.len() {
res.push(state);
return;
}
// Перебор всех вариантов выбора
let mut duplicated = HashSet::<i32>::new();
for i in 0..choices.len() {
let choice = choices[i];
// Отсечение: нельзя выбирать один и тот же элемент повторно и нельзя повторно выбирать равные элементы
if !selected[i] && !duplicated.contains(&choice) {
// Попытка: сделать выбор и обновить состояние
duplicated.insert(choice); // Записать значения уже выбранных элементов
selected[i] = true;
state.push(choice);
// Перейти к следующему выбору
backtrack(state.clone(), choices, selected, res);
// Откат: отменить выбор и восстановить предыдущее состояние
selected[i] = false;
state.pop();
}
}
}
/* Все перестановки II */
fn permutations_ii(nums: &mut [i32]) -> Vec<Vec<i32>> {
let mut res = Vec::new();
backtrack(Vec::new(), nums, &mut vec![false; nums.len()], &mut res);
res
}
/* Driver Code */
pub fn main() {
let mut nums = [1, 2, 2];
let res = permutations_ii(&mut nums);
println!("Входной массив nums = {:?}", &nums);
println!("Все перестановки res = {:?}", &res);
}
@@ -0,0 +1,41 @@
/*
* File: preorder_traversal_i_compact.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode};
use std::{cell::RefCell, rc::Rc};
/* Предварительный обход: пример 1 */
fn pre_order(res: &mut Vec<Rc<RefCell<TreeNode>>>, root: Option<&Rc<RefCell<TreeNode>>>) {
if root.is_none() {
return;
}
if let Some(node) = root {
if node.borrow().val == 7 {
// Записать решение
res.push(node.clone());
}
pre_order(res, node.borrow().left.as_ref());
pre_order(res, node.borrow().right.as_ref());
}
}
/* Driver Code */
pub fn main() {
let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec());
println!("Инициализация двоичного дерева");
print_util::print_tree(root.as_ref().unwrap());
// Предварительный обход
let mut res = Vec::new();
pre_order(&mut res, root.as_ref());
println!("\nВсе узлы со значением 7");
let mut vals = Vec::new();
for node in res {
vals.push(node.borrow().val)
}
println!("{:?}", vals);
}
@@ -0,0 +1,52 @@
/*
* File: preorder_traversal_ii_compact.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode};
use std::{cell::RefCell, rc::Rc};
/* Предварительный обход: пример 2 */
fn pre_order(
res: &mut Vec<Vec<Rc<RefCell<TreeNode>>>>,
path: &mut Vec<Rc<RefCell<TreeNode>>>,
root: Option<&Rc<RefCell<TreeNode>>>,
) {
if root.is_none() {
return;
}
if let Some(node) = root {
// Попытка
path.push(node.clone());
if node.borrow().val == 7 {
// Записать решение
res.push(path.clone());
}
pre_order(res, path, node.borrow().left.as_ref());
pre_order(res, path, node.borrow().right.as_ref());
// Откат
path.pop();
}
}
/* Driver Code */
pub fn main() {
let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec());
println!("Инициализация двоичного дерева");
print_util::print_tree(root.as_ref().unwrap());
// Предварительный обход
let mut path = Vec::new();
let mut res = Vec::new();
pre_order(&mut res, &mut path, root.as_ref());
println!("\nВсе пути от корня к узлу 7");
for path in res {
let mut vals = Vec::new();
for node in path {
vals.push(node.borrow().val)
}
println!("{:?}", vals);
}
}
@@ -0,0 +1,53 @@
/*
* File: preorder_traversal_iii_compact.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode};
use std::{cell::RefCell, rc::Rc};
/* Предварительный обход: пример 3 */
fn pre_order(
res: &mut Vec<Vec<Rc<RefCell<TreeNode>>>>,
path: &mut Vec<Rc<RefCell<TreeNode>>>,
root: Option<&Rc<RefCell<TreeNode>>>,
) {
// Отсечение
if root.is_none() || root.as_ref().unwrap().borrow().val == 3 {
return;
}
if let Some(node) = root {
// Попытка
path.push(node.clone());
if node.borrow().val == 7 {
// Записать решение
res.push(path.clone());
}
pre_order(res, path, node.borrow().left.as_ref());
pre_order(res, path, node.borrow().right.as_ref());
// Откат
path.pop();
}
}
/* Driver Code */
pub fn main() {
let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec());
println!("Инициализация двоичного дерева");
print_util::print_tree(root.as_ref().unwrap());
// Предварительный обход
let mut path = Vec::new();
let mut res = Vec::new();
pre_order(&mut res, &mut path, root.as_ref());
println!("\nВсе пути от корня к узлу 7, не содержащие узлов со значением 3");
for path in res {
let mut vals = Vec::new();
for node in path {
vals.push(node.borrow().val)
}
println!("{:?}", vals);
}
}
@@ -0,0 +1,88 @@
/*
* File: preorder_traversal_iii_template.rs
* Created Time: 2023-07-15
* Author: codingonion (coderonion@gmail.com)
*/
use hello_algo_rust::include::{print_util, vec_to_tree, TreeNode};
use std::{cell::RefCell, rc::Rc};
/* Проверить, является ли текущее состояние решением */
fn is_solution(state: &mut Vec<Rc<RefCell<TreeNode>>>) -> bool {
return !state.is_empty() && state.last().unwrap().borrow().val == 7;
}
/* Записать решение */
fn record_solution(
state: &mut Vec<Rc<RefCell<TreeNode>>>,
res: &mut Vec<Vec<Rc<RefCell<TreeNode>>>>,
) {
res.push(state.clone());
}
/* Проверить, допустим ли этот выбор в текущем состоянии */
fn is_valid(_: &mut Vec<Rc<RefCell<TreeNode>>>, choice: Option<&Rc<RefCell<TreeNode>>>) -> bool {
return choice.is_some() && choice.unwrap().borrow().val != 3;
}
/* Обновить состояние */
fn make_choice(state: &mut Vec<Rc<RefCell<TreeNode>>>, choice: Rc<RefCell<TreeNode>>) {
state.push(choice);
}
/* Восстановить состояние */
fn undo_choice(state: &mut Vec<Rc<RefCell<TreeNode>>>, _: Rc<RefCell<TreeNode>>) {
state.pop();
}
/* Алгоритм бэктрекинга: пример 3 */
fn backtrack(
state: &mut Vec<Rc<RefCell<TreeNode>>>,
choices: &Vec<Option<&Rc<RefCell<TreeNode>>>>,
res: &mut Vec<Vec<Rc<RefCell<TreeNode>>>>,
) {
// Проверить, является ли текущее состояние решением
if is_solution(state) {
// Записать решение
record_solution(state, res);
}
// Перебор всех вариантов выбора
for &choice in choices.iter() {
// Отсечение: проверить допустимость выбора
if is_valid(state, choice) {
// Попытка: сделать выбор и обновить состояние
make_choice(state, choice.unwrap().clone());
// Перейти к следующему выбору
backtrack(
state,
&vec![
choice.unwrap().borrow().left.as_ref(),
choice.unwrap().borrow().right.as_ref(),
],
res,
);
// Откат: отменить выбор и восстановить предыдущее состояние
undo_choice(state, choice.unwrap().clone());
}
}
}
/* Driver Code */
pub fn main() {
let root = vec_to_tree([1, 7, 3, 4, 5, 6, 7].map(|x| Some(x)).to_vec());
println!("Инициализация двоичного дерева");
print_util::print_tree(root.as_ref().unwrap());
// Алгоритм бэктрекинга
let mut res = Vec::new();
backtrack(&mut Vec::new(), &mut vec![root.as_ref()], &mut res);
println!("\nВсе пути от корня к узлу 7, в которых путь не содержит узлов со значением 3");
for path in res {
let mut vals = Vec::new();
for node in path {
vals.push(node.borrow().val)
}
println!("{:?}", vals);
}
}
@@ -0,0 +1,56 @@
/*
* File: subset_sum_i.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Алгоритм бэктрекинга: сумма подмножеств I */
fn backtrack(
state: &mut Vec<i32>,
target: i32,
choices: &[i32],
start: usize,
res: &mut Vec<Vec<i32>>,
) {
// Если сумма подмножества равна target, записать решение
if target == 0 {
res.push(state.clone());
return;
}
// Обойти все варианты выбора
// Отсечение 2: начинать обход с start, чтобы избежать генерации повторяющихся подмножеств
for i in start..choices.len() {
// Отсечение 1: если сумма подмножества превышает target, немедленно завершить цикл
// Это связано с тем, что массив уже отсортирован, следующие элементы больше, и сумма подмножества точно превысит target
if target - choices[i] < 0 {
break;
}
// Попытка: сделать выбор и обновить target и start
state.push(choices[i]);
// Перейти к следующему выбору
backtrack(state, target - choices[i], choices, i, res);
// Откат: отменить выбор и восстановить предыдущее состояние
state.pop();
}
}
/* Решить задачу суммы подмножеств I */
fn subset_sum_i(nums: &mut [i32], target: i32) -> Vec<Vec<i32>> {
let mut state = Vec::new(); // Состояние (подмножество)
nums.sort(); // Отсортировать nums
let start = 0; // Стартовая вершина обхода
let mut res = Vec::new(); // Список результатов (список подмножеств)
backtrack(&mut state, target, nums, start, &mut res);
res
}
/* Driver Code */
pub fn main() {
let mut nums = [3, 4, 5];
let target = 9;
let res = subset_sum_i(&mut nums, target);
println!("Входной массив nums = {:?}, target = {}", &nums, target);
println!("Все подмножества с суммой {}: res = {:?}", target, &res);
}
@@ -0,0 +1,54 @@
/*
* File: subset_sum_i_naive.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Алгоритм бэктрекинга: сумма подмножеств I */
fn backtrack(
state: &mut Vec<i32>,
target: i32,
total: i32,
choices: &[i32],
res: &mut Vec<Vec<i32>>,
) {
// Если сумма подмножества равна target, записать решение
if total == target {
res.push(state.clone());
return;
}
// Перебор всех вариантов выбора
for i in 0..choices.len() {
// Отсечение: если сумма подмножества превышает target, пропустить этот выбор
if total + choices[i] > target {
continue;
}
// Попытка: сделать выбор и обновить элемент и total
state.push(choices[i]);
// Перейти к следующему выбору
backtrack(state, target, total + choices[i], choices, res);
// Откат: отменить выбор и восстановить предыдущее состояние
state.pop();
}
}
/* Решить задачу суммы подмножеств I (с повторяющимися подмножествами) */
fn subset_sum_i_naive(nums: &[i32], target: i32) -> Vec<Vec<i32>> {
let mut state = Vec::new(); // Состояние (подмножество)
let total = 0; // Сумма подмножеств
let mut res = Vec::new(); // Список результатов (список подмножеств)
backtrack(&mut state, target, total, nums, &mut res);
res
}
/* Driver Code */
pub fn main() {
let nums = [3, 4, 5];
let target = 9;
let res = subset_sum_i_naive(&nums, target);
println!("Входной массив nums = {:?}, target = {}", &nums, target);
println!("Все подмножества с суммой {}: res = {:?}", target, &res);
println!("Обратите внимание: результат этого метода содержит повторяющиеся множества");
}
@@ -0,0 +1,61 @@
/*
* File: subset_sum_ii.rs
* Created Time: 2023-07-09
* Author: codingonion (coderonion@gmail.com)
*/
/* Алгоритм бэктрекинга: сумма подмножеств II */
fn backtrack(
state: &mut Vec<i32>,
target: i32,
choices: &[i32],
start: usize,
res: &mut Vec<Vec<i32>>,
) {
// Если сумма подмножества равна target, записать решение
if target == 0 {
res.push(state.clone());
return;
}
// Обойти все варианты выбора
// Отсечение 2: начинать обход с start, чтобы избежать генерации повторяющихся подмножеств
// Отсечение 3: начинать обход с start, чтобы избежать повторного выбора одного и того же элемента
for i in start..choices.len() {
// Отсечение 1: если сумма подмножества превышает target, немедленно завершить цикл
// Это связано с тем, что массив уже отсортирован, следующие элементы больше, и сумма подмножества точно превысит target
if target - choices[i] < 0 {
break;
}
// Отсечение 4: если этот элемент равен элементу слева, значит ветвь поиска повторяется, ее нужно сразу пропустить
if i > start && choices[i] == choices[i - 1] {
continue;
}
// Попытка: сделать выбор и обновить target и start
state.push(choices[i]);
// Перейти к следующему выбору
backtrack(state, target - choices[i], choices, i + 1, res);
// Откат: отменить выбор и восстановить предыдущее состояние
state.pop();
}
}
/* Решить задачу суммы подмножеств II */
fn subset_sum_ii(nums: &mut [i32], target: i32) -> Vec<Vec<i32>> {
let mut state = Vec::new(); // Состояние (подмножество)
nums.sort(); // Отсортировать nums
let start = 0; // Стартовая вершина обхода
let mut res = Vec::new(); // Список результатов (список подмножеств)
backtrack(&mut state, target, nums, start, &mut res);
res
}
/* Driver Code */
pub fn main() {
let mut nums = [4, 4, 5];
let target = 9;
let res = subset_sum_ii(&mut nums, target);
println!("Входной массив nums = {:?}, target = {}", &nums, target);
println!("Все подмножества с суммой {}: res = {:?}", target, &res);
}