LeetCode — обьяснение задачи two_sum на языке Rust

Описание задачи:

Дан массив целых чисел nums и целевое число target, нужно вернуть индексы двух чисел таким образом, чтобы они в сумме давали значение target.

Условие: каждое входное значение может иметь только одно решение и нельзя использовать один и тот же элемент дважды из массива.

Вы можете вернуть ответ в любом порядке.

Пример 1:

Вход: nums = [2,7,11,15], target = 9
Выход: [0,1]
Пояснение: поскольку nums[0] + nums[1] == 9, мы возвращаем [0, 1].

Пример 2:

Вход: nums = [3,2,4], target = 6
Выход: [1,2]

Пример 3:

Вход: nums = [3,3], target = 6
Выход: [0,1]

Пример решения на Rust:

use std::collections::HashMap;

impl Solution {
    pub fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> {
        let mut map = HashMap::new();
        
        for (i, n) in nums.into_iter().enumerate(){
            let diff = target - n;
            
            if let Some(&j) = map.get(&diff){
                return vec![i as i32, j as i32];
            }else{
                map.insert(n, i);
            }
        }
        
        vec![]
    }
}

Этот код реализует классическую задачу «Two Sum» (нахождение двух чисел в массиве, дающих в сумме заданное значение) на языке Rust. Давайте разберём его по частям.


Разбор кода:

1. Импорт HashMap

use std::collections::HashMap;
  • HashMap используется для хранения чисел из массива и их индексов. Это позволяет быстро проверять, встречалось ли нужное число ранее.

2. Реализация метода two_sum

impl Solution {
    pub fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> {
  • impl Solution — реализация методов для структуры Solution (нужно только для leetcode , писать у себя можно и без этого для отладки).
  • two_sum — публичный метод, принимающий:
  • nums: Vec<i32> — вектор (массив) чисел,
  • target: i32 — целевая сумма.
  • Возвращает Vec<i32> — индексы двух чисел, дающих в сумме target.

3. Создание HashMap

let mut map = HashMap::new();
  • Создаётся пустая хеш-таблица (HashMap), где:
  • ключ — число из массива,
  • значение — его индекс.

4. Итерация по массиву

for (i, n) in nums.into_iter().enumerate() {
  • into_iter() — превращает nums в итератор, потребляя его (после этого nums нельзя использовать снова).
  • enumerate() — добавляет индекс i к каждому элементу n.

5. Вычисление разницы (diff)

let diff = target - n;
  • diff — это число, которое нужно найти в HashMap, чтобы n + diff == target.

6. Проверка наличия diff в HashMap

if let Some(&j) = map.get(&diff) {
    return vec![i as i32, j as i32];
}
  • map.get(&diff) — ищет diff в хеш-таблице.
  • Если нашлось (Some(&j)), значит, раньше уже встречалось число diff на позиции j.
  • Возвращаем индексы [i, j] (текущий и найденный).

7. Если diff не найден — сохраняем текущее число

} else {
    map.insert(n, i);
}
  • Если diff не найден, добавляем текущее число n в HashMap с его индексом i.

8. Если пара не найдена — возвращаем пустой вектор

vec![]
  • Если цикл завершился, но решение не найдено, возвращается пустой вектор (хотя в условии задачи обычно гарантируется, что решение есть).

Как это работает?

  1. Пример:
  • nums = [2, 7, 11, 15], target = 9.
  1. Шаги:
  • i=0, n=2diff=77 нет в HashMap → сохраняем {2: 0}.
  • i=1, n=7diff=22 есть в HashMap (j=0) → возвращаем [1, 0].

Сложность алгоритма

  • Время: O(n) — проход по массиву один раз, поиск в HashMap в среднем за O(1).
  • Память: O(n) — в худшем случае храним все элементы.

Ключевые концепции Rust в этом коде

  1. HashMap — эффективный поиск за O(1).
  2. into_iter() — потребляющий итератор (после него nums нельзя использовать).
  3. if let — проверка Option.
  4. Возврат вектора — vec![] создаёт вектор.

Долбаный Aliexpress — паспорт не проходит проверку. Как исправить ?

Я месяц , месяц мать за ногу этого мать его Джека Ма и его криворуких разработчиков решал с поддержкой вопрос почему мой паспорт не проходит проверку после замены его. Все су…. уже сервисы, даже налоговая и даже мать ее пенсионный фонд уже данные обновили и приняли.

У китайцев на алиэкспресс, видимо в силу того, что они переедают своих грибов шитаки, после чего бесконтрольно впадают в нирвану, спустя несколько десятков попыток изменить паспорт, переписать буквы , ввести данные о выдаче как то особо извращенно…Счерт поберри , счерт побеари…. Только алиэкспресс по каким-то своим причинам считал упорно мой паспорт не пригодным для китайского мозга…

В итоге был опять включен режим проверки теорий и метода подбора по-русски «методом тыка».

И что вы думаете помогло?

ФИО нужно писать русскими БОЛЬШИМИ буквами!!

У меня вопрос, вы сука не могли написать , что вводить заглавными или еще проще сделать авто перевод символов в заглавный регистр!!!

Суки!

Проверка знака числа в Rust

В языке Rust можно побитово проверить, является ли число положительным, используя знаковый бит. У целых чисел со знаком (например, i32, i64 и т.д.) старший бит (называемый знаковым битом) указывает на знак числа: если он равен 0, число положительное, если 1 — отрицательное.

Пример проверки для 32-битного целого числа (i32):

fn is_positive(n: i32) -> bool {
// Проверяем, равен ли знаковый бит 0
(n & (1 << 31)) == 0
}

fn main() {
let num = 42;
if is_positive(num) {
println!(«Число {} положительное.», num);
} else {
println!(«Число {} отрицательное.», num);
}
}

Объяснение:

  • 1 << 31 создаёт маску, где установлен только 31-й бит (знаковый бит для i32).
  • n & (1 << 31) выполняет побитовую операцию И, чтобы извлечь значение знакового бита.
  • Если результат равен 0, число положительное, иначе — отрицательное.

Примечание:

  • Для других типов (например, i64) нужно изменить сдвиг: 1 << 63.
  • Этот метод работает только для целых чисел со знаком. Для беззнаковых чисел (u32, u64 и т.д.) все числа по определению неотрицательные, и такая проверка не имеет смысла.

Если вам нужно просто проверить знак числа, можно использовать встроенные методы, например:

fn main() {
let num = 42;
if num.is_positive() {
println!(«Число {} положительное.», num);
} else {
println!(«Число {} отрицательное.», num);
}
}

Метод is_positive() доступен для всех целых чисел со знаком в Rust.


В языке Rust (и в программировании в целом) числовые маски — это специальные значения, которые используются для выполнения побитовых операций над числами. Маски позволяют извлекать, устанавливать, сбрасывать или инвертировать определённые биты в числе. Они часто применяются для работы с флагами, битовыми полями или для оптимизации определённых операций.

Основные побитовые операции

В Rust поддерживаются следующие побитовые операции, которые часто используются с масками:

  1. И (AND, &): Возвращает 1 только если оба соответствующих бита равны 1.
  2. ИЛИ (OR, |): Возвращает 1 если хотя бы один из соответствующих битов равен 1.
  3. Исключающее ИЛИ (XOR, ^): Возвращает 1 если соответствующие биты различны.
  4. НЕ (NOT, !): Инвертирует все биты числа.
  5. Сдвиг влево (<<): Сдвигает биты числа влево, заполняя освободившиеся биты нулями.
  6. Сдвиг вправо (>>): Сдвигает биты числа вправо (для беззнаковых чисел заполняет нулями, для знаковых — зависит от реализации).

Примеры числовых масок

  1. Извлечение определённых битов:
    Если нужно извлечь младшие 4 бита числа, можно использовать маску 0b1111 (или 0xF в шестнадцатеричном формате):
   let num = 0b10101010; // Пример числа
   let mask = 0b00001111; // Маска для извлечения младших 4 бит
   let result = num & mask; // Результат: 0b1010
   println!("{:b}", result); // Вывод: 1010
  1. Установка битов:
    Чтобы установить определённые биты в 1, используется операция ИЛИ (|):
   let num = 0b10101010;
   let mask = 0b00001111; // Маска для установки младших 4 бит
   let result = num | mask; // Результат: 0b10101111
   println!("{:b}", result); // Вывод: 10101111
  1. Сброс битов:
    Чтобы сбросить определённые биты в 0, используется маска с инвертированными битами и операция И (&):
   let num = 0b10101010;
   let mask = !0b00001111; // Инвертированная маска для сброса младших 4 бит
   let result = num & mask; // Результат: 0b10100000
   println!("{:b}", result); // Вывод: 10100000
  1. Инвертирование битов:
    Чтобы инвертировать определённые биты, используется операция XOR (^):
   let num = 0b10101010;
   let mask = 0b00001111; // Маска для инвертирования младших 4 бит
   let result = num ^ mask; // Результат: 0b10100101
   println!("{:b}", result); // Вывод: 10100101
  1. Проверка битов:
    Чтобы проверить, установлен ли определённый бит, используется маска и операция И (&):
   let num = 0b10101010;
   let mask = 0b00001000; // Маска для проверки 4-го бита
   if num & mask != 0 {
       println!("4-й бит установлен!");
   } else {
       println!("4-й бит не установлен.");
   }

Применение числовых масок

Числовые маски часто используются в следующих сценариях:

  • Работа с флагами (например, в системных вызовах или библиотеках).
  • Оптимизация памяти (хранение нескольких значений в одном числе).
  • Кодирование и декодирование данных.
  • Низкоуровневое программирование (например, работа с регистрами микроконтроллеров).

Пример: Хранение флагов

const FLAG_A: u8 = 0b00000001; // Флаг A
const FLAG_B: u8 = 0b00000010; // Флаг B
const FLAG_C: u8 = 0b00000100; // Флаг C

let flags = FLAG_A | FLAG_C; // Устанавливаем флаги A и C

// Проверяем, установлен ли флаг B
if flags & FLAG_B != 0 {
    println!("Флаг B установлен.");
} else {
    println!("Флаг B не установлен.");
}

Заключение

Числовые маски — это мощный инструмент для работы с битами в Rust. Они позволяют эффективно управлять отдельными битами чисел, что особенно полезно в низкоуровневом программировании и оптимизации.



Установка Rust — ошибка ‘curl: (23) client returned ERROR on write of … bytes’

Ошибка может возникать из-за недостатка места, которое необходимо при установке. По умолчанию временные установочные файлы скачиваются в TMPDIR.

Если возникает такая ошибка — то лучше ее переопределить и указать место на диске, в котором достаточно места для скачивания установочных файлов:

export TMPDIR=/home/user/tmp
export TEMPDIR=${TMPDIR}

Затем повторить установку:

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Rust — подготовленные запросы в PostgreSQL с указанием типа

cargo.toml


[dependencies]
postgres = { version = "0.19.9", features = ["with-uuid-1", "with-chrono-0_4"] }
uuid = { version = "1.11.0", features = ["v4"] }
chrono = "0.4.38"

main.rs

use postgres::{Client, NoTls};
use std::error::Error;
use uuid::Uuid;
use chrono::{NaiveDateTime};


fn main() -> Result<(), Box<dyn Error>> {
    let mut conn = Client::connect(
        "postgresql://postgres:jopa@localhost:5432/postgres",
        NoTls)
    .unwrap();

    let stuff_id = Uuid::new_v4();
    let date_str = "2020-04-12 22:10:57";
    let naive_datetime = NaiveDateTime::parse_from_str(date_str, "%Y-%m-%d %H:%M:%S").unwrap();

    conn.execute(
        "insert into test (stuff_id, naive_datetime) values ($1, $2)",
        &[&stuff_id, &naive_datetime],
    )?;

    Ok(())
}

Rust — установка через proxy c выводом расширенной информации об установке

Пришлось извращаться с установкой внутри корп. сети с закрытым прямым доступом в Интернет и еще стала выпадать ошибка что на девайсе не достаточно места.

По умолчанию Rust для установки использует домашнюю директорию пользователя, поэтому если видите такую ошибку с местом — увеличьте размер тома.

Далее чтобы произвести установку через прокси нужно к стандартному curl-запросу добавить следующие параметры:

curl -x http://proxy.ru:port --proxy-user 'user:pass' --insecure --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -v -y

Rust — SSH2 sftp download file

use std::net::TcpStream;
use std::io::Read;
use ssh2::Session;
use std::path::Path;

fn main() {
    let tcp = TcpStream::connect("127.0.0.1:22").unwrap();
    let mut sess = Session::new().unwrap();
sess.set_tcp_stream(tcp);
sess.handshake().unwrap();
sess.userauth_password("user", "password").unwrap();
    let mut contents:Vec<u8> = Vec::new();
    let sftp = sess.sftp().unwrap();
    let mut stream = sftp.open(Path::new("/tmp/test.txt")).unwrap();
             stream.read_to_end(&mut contents).unwrap();
             let _ = std::fs::write(r"/tmp/test_out.txt", &contents);
}

Rust — sftp upload file

use std::net::TcpStream;
use std::io::Write;
use std::io::Read;
use std::fs::File;
use ssh2::Session;
use std::path::Path;


fn main() {

    let tcp = TcpStream::connect("127.0.0.1:22").unwrap();
    let mut sess = Session::new().unwrap();
sess.set_tcp_stream(tcp);
sess.handshake().unwrap();
sess.userauth_password("user", "pass").unwrap();
     
     let sftp = sess.sftp().unwrap();
     let mut local_file = File::open("/tmp/test.txt").expect("no file found");  
     let mut buffer:Vec<u8> = Vec::new();
     let _ :u64 = local_file.read_to_end(&mut buffer).unwrap().try_into().unwrap();

sftp.create(&Path::new("/tmp/file.json"))
    .unwrap()
    .write_all(&buffer)
    .unwrap();
}

Решено! Rust — не собирается под musl — ругаeтся на openssl в Linux.

Если вы решили использовать в своем проекте то, что нужнается в Openssl — будьте готовы что можете столкнуться с кучей ошибок при сборке, особенно если собираете под стандартную реализацию libc в musl.

При сборке cargo вам вывалит что -то подобное:

OPENSSL_DIR unset
  cargo:rerun-if-env-changed=OPENSSL_NO_PKG_CONFIG
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_x86_64-unknown-linux-musl
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS_x86_64_unknown_linux_musl
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_ALLOW_CROSS
  cargo:rerun-if-env-changed=PKG_CONFIG_ALLOW_CROSS
  cargo:rerun-if-env-changed=PKG_CONFIG_x86_64-unknown-linux-musl
  cargo:rerun-if-env-changed=PKG_CONFIG_x86_64_unknown_linux_musl
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG
  cargo:rerun-if-env-changed=PKG_CONFIG
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64-unknown-linux-musl
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR_x86_64_unknown_linux_musl
  cargo:rerun-if-env-changed=TARGET_PKG_CONFIG_SYSROOT_DIR
  cargo:rerun-if-env-changed=PKG_CONFIG_SYSROOT_DIR
  run pkg_config fail: pkg-config has not been configured to support cross-compilation.

  Install a sysroot for the target platform and configure it via
  PKG_CONFIG_SYSROOT_DIR and PKG_CONFIG_PATH, or install a
  cross-compiling wrapper for pkg-config and set it via
  PKG_CONFIG environment variable.

  --- stderr
  thread 'main' panicked at /home/.cargo/registry/src/index.crates.io-6f17d22bba15001f/openssl-sys-0.9.102/build/find_normal.rs:190:5:


  Could not find directory of OpenSSL installation, and this `-sys` crate cannot
  proceed without this knowledge. If OpenSSL is installed and this crate had
  trouble finding it,  you can set the `OPENSSL_DIR` environment variable for the
  compilation process.

  Make sure you also have the development packages of openssl installed.
  For example, `libssl-dev` on Ubuntu or `openssl-devel` on Fedora.

  If you're in a situation where you think the directory *should* be found
  automatically, please open a bug at https://github.com/sfackler/rust-openssl
  and include information about your system as well as this message.

  $HOST = x86_64-unknown-linux-gnu
  $TARGET = x86_64-unknown-linux-musl
  openssl-sys = 0.9.102

У меня такая фигня пошла, когда я решил добавить Sentry в свой проект.

Решение следующее:

Выполняем команды:

sudo apt-get update
sudo apt-get install -y musl-dev musl-tools linux-headers-$(uname -r)

sudo ln -s /usr/include/x86_64-linux-gnu/asm /usr/include/x86_64-linux-musl/asm && ln -s /usr/include/asm-generic /usr/include/x86_64-linux-musl/asm-generic && ln -s /usr/include/linux /usr/include/x86_64-linux-musl/linux
sudo mkdir /musl
wget https://github.com/openssl/openssl/archive/OpenSSL_1_1_1f.tar.gz
tar zxf OpenSSL_1_1_1f.tar.gz 
cd openssl-OpenSSL_1_1_1f/
CC="musl-gcc -fPIE -pie -static -idirafter /usr/include/ -idirafter /usr/include/x86_64-linux-gnu/" ./Configure no-shared no-async --prefix=/musl --openssldir=/musl/ssl linux-x86_64
make depend
make -j$(nproc)
sudo make install

Экспортируем переменные окружения:
export PKG_CONFIG_ALLOW_CROSS=1
export OPENSSL_STATIC=true
export OPENSSL_DIR=/musl

Пробуем выполнять сборку:
cargo build --release --target=x86_64-unknown-linux-musl