using System;
using System.Collections.Generic;
// C# has a built-in HashSet<T> — no workaround needed
var set = new HashSet<int>();
set.Add(1);
set.Add(2);
set.Add(3);
set.Add(4); // {1, 2, 3, 4}
bool added = set.Add(2); // false — duplicate ignored
Console.WriteLine(added);
Console.WriteLine(set.Contains(2)); // true — O(1)
set.Remove(3); // {1, 2, 4}
// Create a set straight from a collection
var fromArray = new HashSet<int>([1, 2, 3, 4]);
Console.WriteLine(fromArray.Contains(2)); // true — O(1)
# Python has a built-in set type
s = set()
s.add(1)
s.add(2)
s.add(3)
s.add(4) # {1, 2, 3, 4}
s.add(2) # {1, 2, 3, 4} — duplicate ignored
print(2 in s) # True — O(1)
s.discard(3) # {1, 2, 4}; discard() does not raise if missing
# Set literal / from an iterable
s = {1, 2, 3, 4}
s = set([1, 2, 3, 4])
print(2 in s) # True — O(1)
## Операции с множествами
Операция
PHP
Сложность
Добавить
$s[$x] = true
O(1)
Удалить
unset($s[$x])
O(1)
Проверка
isset($s[$x])
O(1)
Объединение
$s1 + $s2
O(n+m)
Пересечение
array_intersect_key($s1, $s2)
O(min(n,m))
Разность
array_diff_key($s1, $s2)
O(n)
Множество A: {1, 2, 3, 4}
Множество B: {3, 4, 5, 6}
A | B = {1, 2, 3, 4, 5, 6} (объединение)
A & B = {3, 4} (пересечение)
A - B = {1, 2} (разность)
A ^ B = {1, 2, 5, 6} (симметричная разность)
func containsDuplicate(nums []int) bool {
seen := map[int]bool{}
for _, num := range nums {
if seen[num] {
return true
}
seen[num] = true
}
return false
}
// [1, 2, 3, 1] -> true
// [1, 2, 3, 4] -> false
using System.Collections.Generic;
static bool ContainsDuplicate(int[] nums) => new HashSet<int>(nums).Count != nums.Length;
// Or explicitly, with an early exit:
static bool ContainsDuplicateV2(int[] nums)
{
var seen = new HashSet<int>();
foreach (int num in nums)
{
// Add returns false if the element is already present
if (!seen.Add(num))
{
return true;
}
}
return false;
}
// [1, 2, 3, 1] -> true
// [1, 2, 3, 4] -> false
def contains_duplicate(nums: list[int]) -> bool:
return len(set(nums)) != len(nums)
# Or explicitly, with an early exit:
def contains_duplicate_v2(nums: list[int]) -> bool:
seen: set[int] = set()
for num in nums:
if num in seen:
return True
seen.add(num)
return False
# [1, 2, 3, 1] -> True
# [1, 2, 3, 4] -> False
// singleNumberSet uses a set to find the unique element.
func singleNumberSet(nums []int) int {
seen := map[int]bool{}
for _, num := range nums {
if seen[num] {
delete(seen, num)
} else {
seen[num] = true
}
}
for num := range seen {
return num
}
return 0
}
// singleNumberXor uses XOR for O(1) memory.
func singleNumberXor(nums []int) int {
result := 0
for _, num := range nums {
result ^= num
}
return result
}
// [2, 2, 1] -> 1
// [4, 1, 2, 1, 2] -> 4
// 4^1^2^1^2 = 4^(1^1)^(2^2) = 4^0^0 = 4
using System.Collections.Generic;
using System.Linq;
// Solution via HashSet
static int SingleNumberSet(int[] nums)
{
var seen = new HashSet<int>();
foreach (int num in nums)
{
// Add returns false on a repeat — drop the pair
if (!seen.Add(num))
{
seen.Remove(num);
}
}
return seen.Single();
}
// Optimal solution: XOR (O(1) memory)
static int SingleNumberXor(int[] nums) => nums.Aggregate(0, (acc, num) => acc ^ num);
// [2, 2, 1] -> 1
// [4, 1, 2, 1, 2] -> 4
// 4^1^2^1^2 = 4^(1^1)^(2^2) = 4^0^0 = 4
from functools import reduce
from operator import xor
# Solution via set
def single_number_set(nums: list[int]) -> int:
seen: set[int] = set()
for num in nums:
if num in seen:
seen.discard(num)
else:
seen.add(num)
return seen.pop()
# Optimal solution: XOR (O(1) memory)
def single_number_xor(nums: list[int]) -> int:
return reduce(xor, nums, 0)
# [2, 2, 1] -> 1
# [4, 1, 2, 1, 2] -> 4
# 4^1^2^1^2 = 4^(1^1)^(2^2) = 4^0^0 = 4
## Задача 4: Happy Number
Условие: число «счастливое», если последовательность сумм квадратов цифр приводит к 1.
func isHappy(n int) bool {
seen := map[int]bool{}
for n != 1 {
if seen[n] {
return false // Cycle detected
}
seen[n] = true
// Sum of squares of digits
total := 0
for n > 0 {
digit := n % 10
total += digit * digit
n /= 10
}
n = total
}
return true
}
// n = 19:
// 1^2 + 9^2 = 82 -> 68 -> 100 -> 1 -> true!
// n = 2:
// 4 -> 16 -> 37 -> 58 -> 89 -> 145 -> 42 -> 20 -> 4 -> CYCLE! false
using System.Collections.Generic;
static bool IsHappy(int n)
{
var seen = new HashSet<int>();
while (n != 1)
{
// Add returns false when n was already seen
if (!seen.Add(n))
{
return false; // Cycle detected
}
// Sum of squares of digits
int total = 0;
while (n > 0)
{
int digit = n % 10;
total += digit * digit;
n /= 10;
}
n = total;
}
return true;
}
// n = 19:
// 1^2 + 9^2 = 82 -> 68 -> 100 -> 1 -> true!
// n = 2:
// 4 -> 16 -> 37 -> 58 -> 89 -> 145 -> 42 -> 20 -> 4 -> CYCLE! false
def is_happy(n: int) -> bool:
seen: set[int] = set()
while n != 1:
if n in seen:
return False # Cycle detected
seen.add(n)
# Sum of squares of digits
n = sum(int(digit) ** 2 for digit in str(n))
return True
# n = 19:
# 1**2 + 9**2 = 82 -> 68 -> 100 -> 1 -> True!
# n = 2:
# 4 -> 16 -> 37 -> 58 -> 89 -> 145 -> 42 -> 20 -> 4 -> CYCLE! False
func isValidSudoku(board [][]byte) bool {
var rows, cols, boxes [9]map[byte]bool
for i := 0; i < 9; i++ {
rows[i] = map[byte]bool{}
cols[i] = map[byte]bool{}
boxes[i] = map[byte]bool{}
}
for i := 0; i < 9; i++ {
for j := 0; j < 9; j++ {
num := board[i][j]
if num == '.' {
continue
}
boxIdx := (i/3)*3 + j/3
if rows[i][num] || cols[j][num] || boxes[boxIdx][num] {
return false
}
rows[i][num] = true
cols[j][num] = true
boxes[boxIdx][num] = true
}
}
return true
}
using System.Collections.Generic;
static bool IsValidSudoku(char[][] board)
{
var rows = new HashSet<char>[9];
var cols = new HashSet<char>[9];
var boxes = new HashSet<char>[9];
for (int i = 0; i < 9; i++)
{
rows[i] = [];
cols[i] = [];
boxes[i] = [];
}
for (int i = 0; i < 9; i++)
{
for (int j = 0; j < 9; j++)
{
char num = board[i][j];
if (num == '.')
{
continue;
}
int boxIdx = i / 3 * 3 + j / 3;
// Add returns false when the digit is already in that group
if (!rows[i].Add(num) || !cols[j].Add(num) || !boxes[boxIdx].Add(num))
{
return false;
}
}
}
return true;
}
from collections import defaultdict
def is_valid_sudoku(board: list[list[str]]) -> bool:
rows: defaultdict[int, set[str]] = defaultdict(set)
cols: defaultdict[int, set[str]] = defaultdict(set)
boxes: defaultdict[int, set[str]] = defaultdict(set)
for i, row in enumerate(board):
for j, num in enumerate(row):
if num == ".":
continue
box_idx = i // 3 * 3 + j // 3
if num in rows[i] or num in cols[j] or num in boxes[box_idx]:
return False
rows[i].add(num)
cols[j].add(num)
boxes[box_idx].add(num)
return True
## Задача 6: Missing Number
<?php
declare(strict_types=1);
// Via Set:
/**
* @param int[] $nums
*/
function missingNumberSet(array $nums): int
{
$set = array_flip($nums);
$n = count($nums);
for ($i = 0; $i <= $n; $i++) {
if (!isset($set[$i])) {
return $i;
}
}
return $n;
}
// Via math (better):
/**
* @param int[] $nums
*/
function missingNumberMath(array $nums): int
{
$n = count($nums);
$expectedSum = intdiv($n * ($n + 1), 2);
return $expectedSum - array_sum($nums);
}
// Via XOR (O(1) memory):
/**
* @param int[] $nums
*/
function missingNumberXor(array $nums): int
{
$result = count($nums);
foreach ($nums as $i => $num) {
$result ^= $i ^ $num;
}
return $result;
}
// [3, 0, 1] -> 2
// [0, 1] -> 2
// missingNumberSet uses a set for O(1) lookup.
func missingNumberSet(nums []int) int {
set := map[int]bool{}
for _, n := range nums {
set[n] = true
}
for i := 0; i <= len(nums); i++ {
if !set[i] {
return i
}
}
return len(nums)
}
// missingNumberMath uses Gauss formula.
func missingNumberMath(nums []int) int {
n := len(nums)
expectedSum := n * (n + 1) / 2
actualSum := 0
for _, num := range nums {
actualSum += num
}
return expectedSum - actualSum
}
// missingNumberXor uses XOR for O(1) memory.
func missingNumberXor(nums []int) int {
result := len(nums)
for i, num := range nums {
result ^= i ^ num
}
return result
}
// [3, 0, 1] -> 2
// [0, 1] -> 2
using System.Collections.Generic;
using System.Linq;
// Via HashSet
static int MissingNumberSet(int[] nums)
{
var set = new HashSet<int>(nums);
for (int i = 0; i <= nums.Length; i++)
{
if (!set.Contains(i))
{
return i;
}
}
return nums.Length;
}
// Via math (better)
static int MissingNumberMath(int[] nums)
{
int n = nums.Length;
return n * (n + 1) / 2 - nums.Sum();
}
// Via XOR (O(1) memory)
static int MissingNumberXor(int[] nums)
{
int result = nums.Length;
for (int i = 0; i < nums.Length; i++)
{
result ^= i ^ nums[i];
}
return result;
}
// [3, 0, 1] -> 2
// [0, 1] -> 2
from functools import reduce
from operator import xor
# Via set
def missing_number_set(nums: list[int]) -> int:
num_set = set(nums)
return next(i for i in range(len(nums) + 1) if i not in num_set)
# Via math (better)
def missing_number_math(nums: list[int]) -> int:
n = len(nums)
return n * (n + 1) // 2 - sum(nums)
# Via XOR (O(1) memory)
def missing_number_xor(nums: list[int]) -> int:
return reduce(xor, (i ^ num for i, num in enumerate(nums)), len(nums))
# [3, 0, 1] -> 2
# [0, 1] -> 2
## Когда использовать Set vs HashMap
Задача
Структура
Проверка «был ли такой элемент»
Set
Подсчёт количества
HashMap
Поиск комплемента с индексом
HashMap
Обнаружение цикла
Set
Уникальные элементы
Set
Группировка по ключу
HashMap
Пересечение/объединение множеств
Set
Маппинг ключ-значение
HashMap
Set через ассоциативный массив
<?php
declare(strict_types=1);
// PHP has no built-in Set class — use associative array
// Create set from array
$set = array_flip([1, 2, 3, 4, 5]);
// Check membership: O(1)
isset($set[3]); // true
// Add element
$set[6] = true;
// Remove element
unset($set[3]);
// Set operations
$a = array_flip([1, 2, 3, 4]);
$b = array_flip([3, 4, 5, 6]);
$union = $a + $b; // Union
$intersect = array_intersect_key($a, $b); // Intersection
$diff = array_diff_key($a, $b); // Difference
$symDiff = array_diff_key($a, $b) + array_diff_key($b, $a); // Symmetric difference
package main
func main() {
// Go has no built-in Set — use map[T]bool or map[T]struct{}
// Create set from slice
arr := []int{1, 2, 3, 4, 5}
set := map[int]bool{}
for _, v := range arr {
set[v] = true
}
// Check membership: O(1)
_ = set[3] // true
// Add element
set[6] = true
// Remove element
delete(set, 3)
// Set operations
a := map[int]bool{1: true, 2: true, 3: true, 4: true}
b := map[int]bool{3: true, 4: true, 5: true, 6: true}
// Union
union := map[int]bool{}
for k := range a { union[k] = true }
for k := range b { union[k] = true }
// Intersection
intersect := map[int]bool{}
for k := range a {
if b[k] { intersect[k] = true }
}
// Difference (a - b)
diff := map[int]bool{}
for k := range a {
if !b[k] { diff[k] = true }
}
// Symmetric difference
symDiff := map[int]bool{}
for k := range a {
if !b[k] { symDiff[k] = true }
}
for k := range b {
if !a[k] { symDiff[k] = true }
}
}
using System.Collections.Generic;
// C# has a real HashSet<T> — no associative-array tricks needed
// Create set from array
var set = new HashSet<int>([1, 2, 3, 4, 5]);
// Check membership: O(1)
set.Contains(3); // true
// Add element
set.Add(6);
// Remove element
set.Remove(3);
// Set operations — the methods mutate the receiver, so copy first
var a = new HashSet<int>([1, 2, 3, 4]);
var b = new HashSet<int>([3, 4, 5, 6]);
var union = new HashSet<int>(a);
union.UnionWith(b); // {1, 2, 3, 4, 5, 6}
var intersect = new HashSet<int>(a);
intersect.IntersectWith(b); // {3, 4}
var diff = new HashSet<int>(a);
diff.ExceptWith(b); // {1, 2}
var symDiff = new HashSet<int>(a);
symDiff.SymmetricExceptWith(b); // {1, 2, 5, 6}
# Python has a built-in set with operator syntax
# Create set from a list
s = set([1, 2, 3, 4, 5]) # or the literal {1, 2, 3, 4, 5}
# Check membership: O(1)
print(3 in s) # True
# Add element
s.add(6)
# Remove element
s.discard(3) # discard() does not raise if the element is missing
# Set operations — the operators return a new set
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
union = a | b # {1, 2, 3, 4, 5, 6}
intersect = a & b # {3, 4}
diff = a - b # {1, 2}
sym_diff = a ^ b # {1, 2, 5, 6}
> **Запомни:** HashSet — это когда тебе не нужны значения, только быстрая проверка «есть или нет». Типичные сигналы: «найти дубликат», «обнаружить цикл», «проверить уникальность», «пересечение двух коллекций». Когда можно заменить Set на математику или XOR — делай это для O(1) памяти. В PHP используй `array_flip()` для создания Set из массива и `isset()` для O(1) проверки.