Задача: №16. 3Sum Closest #medium
Условие:
Решение:
Пояснение:
1: Сортировка и начальная инициализацияsort(nums.begin(), nums.end()); // Сортировка массива nums
int front;int sum = nums[0] + nums[1] + nums[2]; // Инициализация переменной для хранения наиболее близкой суммы
int sum1 = 0; // Переменная для текущей суммы трех чисел
1. Массив nums сортируется для удобства работы с двумя указателями (front и back) в последующих шагах.2. sum инициализируется суммой первых трех элементов массива (предполагается, что массив содержит как минимум 3 элемента).
3. sum1 будет использоваться для хранения текущей суммы трех чисел.
2: Основной цикл по каждому элементу
1. Инициализация указателей:
front = i + 1; int back = nums.size() - 1;
front и back - это указатели на элементы после текущего и последний элемент массива соответственно.
2. Цикл с двумя указателями:
while(front < back) {
sum1 = nums[front] + nums[back] + nums[i];
Цикл продолжается, пока front меньше back. Внутри цикла вычисляется текущая сумма трех элементов.
- Обновление sum, если текущая сумма ближе к целевому значению:
if (abs(sum1 - target) <= abs(sum - target)) { sum = sum1;
}
Если абсолютная разница между sum1 и target меньше или равна разнице между sum и target, обновляем sum.
- Движение указателей:
;
Если текущая сумма больше целевого значения (target), смещаем указатель back влево, чтобы уменьшить сумму.
Если текущая сумма меньше целевого значения, смещаем указатель front вправо, чтобы увеличить сумму. Если текущая сумма равна целевому значению (target), возвращаем текущую сумму, так как это наилучший возможный результат.
3: Возвращение результата
return sum;
Метод возвращает наиболее близкую сумму трех чисел к заданному значению target.
### Временная сложность- Сложность сортировки массива O(n log n).
- Внешний цикл O(n) с внутренним циклом O(n), что в сумме даёт O(n^2).Итого, временная сложность этого алгоритма в худшем случае составляет O(n^2).
Условие:
Учитывая целочисленный массив nums длины n и целочисленную цель, найдите три целых числа в nums, сумма которых наиболее близка к цели. Возвращает сумму трех целых чисел. Вы можете предположить, что каждый вход будет иметь ровно одно решение.
Решение:
class Solution {
public:
int threeSumClosest(vector<int>& nums, int target) {
sort(nums.begin(),nums.end());
int front;
int sum=nums[0]+nums[1]+nums[2],sum1=0;
for(int i=0;i<nums.size();i++){
front=i+1;
int back=nums.size()-1;
while(front<back){
sum1=nums[front]+nums[back]+nums[i];
if(abs(sum1-target)<=abs(sum-target)){
sum=sum1;
}
if(sum1>target)
back--;
else if(sum1<target)
front++;
else return sum1;
}
}
return sum;
}
};Пояснение:
1: Сортировка и начальная инициализацияsort(nums.begin(), nums.end()); // Сортировка массива nums
int front;int sum = nums[0] + nums[1] + nums[2]; // Инициализация переменной для хранения наиболее близкой суммы
int sum1 = 0; // Переменная для текущей суммы трех чисел
1. Массив nums сортируется для удобства работы с двумя указателями (front и back) в последующих шагах.2. sum инициализируется суммой первых трех элементов массива (предполагается, что массив содержит как минимум 3 элемента).
3. sum1 будет использоваться для хранения текущей суммы трех чисел.
2: Основной цикл по каждому элементу
1. Инициализация указателей:
front = i + 1; int back = nums.size() - 1;
front и back - это указатели на элементы после текущего и последний элемент массива соответственно.
2. Цикл с двумя указателями:
while(front < back) {
sum1 = nums[front] + nums[back] + nums[i];
Цикл продолжается, пока front меньше back. Внутри цикла вычисляется текущая сумма трех элементов.
- Обновление sum, если текущая сумма ближе к целевому значению:
if (abs(sum1 - target) <= abs(sum - target)) { sum = sum1;
}
Если абсолютная разница между sum1 и target меньше или равна разнице между sum и target, обновляем sum.
- Движение указателей:
;
Если текущая сумма больше целевого значения (target), смещаем указатель back влево, чтобы уменьшить сумму.
Если текущая сумма меньше целевого значения, смещаем указатель front вправо, чтобы увеличить сумму. Если текущая сумма равна целевому значению (target), возвращаем текущую сумму, так как это наилучший возможный результат.
3: Возвращение результата
return sum;
Метод возвращает наиболее близкую сумму трех чисел к заданному значению target.
### Временная сложность- Сложность сортировки массива O(n log n).
- Внешний цикл O(n) с внутренним циклом O(n), что в сумме даёт O(n^2).Итого, временная сложность этого алгоритма в худшем случае составляет O(n^2).
👍4
Задача: №17. Letter Combinations of a Phone Number #medium
Условие:
Решение:
Пояснение:
1. void find(string digits, vector<string> v, vector<string>& res, string s, int k):
- Эта функция является рекурсивной.
- Она принимает следующие параметры:
- digits: входная цифровая строка.
- v: вектор строк, где каждая строка содержит буквы, соответствующие цифрам от 0 до 9.
- res: вектор, в который будут добавляться результирующие строки.
- s: текущая строка, которая формируется в процессе рекурсии.
- k: индекс текущей цифры в digits.
- Если k равен размеру digits, это означает, что мы нашли полную комбинацию букв, поэтому добавляем s в res.
- Иначе, для текущей цифры digits[k] мы итерируемся по соответствующим буквам в v[digits[k] - '0'] и добавляем их к s. Затем рекурсивно вызываем find() с увеличенным k, чтобы найти следующую часть комбинации.
- После рекурсивного вызова, мы удаляем последний символ из s, чтобы вернуться к предыдущей части комбинации.
2. vector<string> letterCombinations(string digits):
- Эта функция является главной, которая вызывает find().
- Если digits пуст, возвращаем пустой вектор.
- Создаем вектор v, где каждая строка содержит буквы, соответствующие цифрам от 0 до 9.
- Инициализируем k = 0 и пустую строку s.
- Вызываем find() с параметрами digits, v, res, s и k.
- Возвращаем res, содержащий все найденные комбинации букв.
Условие:
Учитывая строку, содержащую цифры от 2 до 9 включительно, верните все возможные комбинации букв, которые может представлять число. Верните ответ в любом порядке. Соответствие цифр буквам (как на кнопках телефона) приведено ниже. Обратите внимание, что 1 не соответствует никаким буквам.
Решение:
class Solution {
public:
void find(string digits,vector<string>v,vector<string>&res,string s,int k){
if(k>=digits.size()){
res.push_back(s);
return;
}
int a = digits[k] - '0';
for(int i=0;i<v[a].size();i++){
s+=v[a][i];
find(digits,v,res,s,k+1);
s.pop_back();
}
}
vector<string> letterCombinations(string digits) {
vector<string>res;
if(digits.size()==0) return res;
vector<string>v={"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
int k=0;
string s="";
find(digits,v,res,s,k);
return res;
}
};Пояснение:
1. void find(string digits, vector<string> v, vector<string>& res, string s, int k):
- Эта функция является рекурсивной.
- Она принимает следующие параметры:
- digits: входная цифровая строка.
- v: вектор строк, где каждая строка содержит буквы, соответствующие цифрам от 0 до 9.
- res: вектор, в который будут добавляться результирующие строки.
- s: текущая строка, которая формируется в процессе рекурсии.
- k: индекс текущей цифры в digits.
- Если k равен размеру digits, это означает, что мы нашли полную комбинацию букв, поэтому добавляем s в res.
- Иначе, для текущей цифры digits[k] мы итерируемся по соответствующим буквам в v[digits[k] - '0'] и добавляем их к s. Затем рекурсивно вызываем find() с увеличенным k, чтобы найти следующую часть комбинации.
- После рекурсивного вызова, мы удаляем последний символ из s, чтобы вернуться к предыдущей части комбинации.
2. vector<string> letterCombinations(string digits):
- Эта функция является главной, которая вызывает find().
- Если digits пуст, возвращаем пустой вектор.
- Создаем вектор v, где каждая строка содержит буквы, соответствующие цифрам от 0 до 9.
- Инициализируем k = 0 и пустую строку s.
- Вызываем find() с параметрами digits, v, res, s и k.
- Возвращаем res, содержащий все найденные комбинации букв.
👍1
Задача: №18. 4Sum #medium
Условие:
Решение:
Пояснение:
1. vector<vector<int>> fourSum(vector<int>& nums, int target):
- Это основная функция, которая принимает вектор nums и целевое значение target.
- Она возвращает вектор всех найденных четверок элементов.
2. Инициализация:
- Получаем размер вектора nums и сохраняем его в n.
- Создаем вектор ans, который будет хранить все найденные четверки.
- Сортируем вектор nums в порядке возрастания.
3. Основной цикл:
- Внешний цикл for перебирает все возможные значения a (от 0 до n-1).
- Внутренний цикл for перебирает все возможные значения b (от a+1 до n-1).
- Затем в цикле while мы используем два указателя c и d, которые двигаются навстречу друг другу.
4. Логика поиска:
- Вычисляем сумму текущей четверки (a, b, c, d) и сравниваем ее с target.
- Если сумма меньше target, увеличиваем c, чтобы увеличить сумму.
- Если сумма больше target, уменьшаем d, чтобы уменьшить сумму.
- Если сумма равна target, добавляем текущую четверку в ans, но только если она еще не была добавлена. Для этого мы используем стандартную функцию find() для проверки, есть ли такая четверка в ans.
- После этого увеличиваем c и уменьшаем d, чтобы найти следующую четверку.
5. Возвращаем ans:
- После завершения всех циклов возвращаем вектор ans, содержащий все найденные четверки.
Условие:
Учитывая массив nums из n целых чисел, верните массив всех уникальных четверок [nums[a], nums[b], nums[c], nums[d]] таких, что:
0 <= a, b, c, d < na, b, c и d различны.
nums[a] + nums[b] + nums[c] + nums[d] == цельВы можете вернуть ответ в любом порядке.
Решение:
class Solution {
public:
vector<vector<int>> fourSum(vector<int>& nums, int target) {
int n=nums.size();
vector<vector<int>>ans;
sort(nums.begin(),nums.end());
for(int a=0;a<n;a++)
{
for(int b=a+1;b<n;b++)
{
int c=b+1;
int d=n-1;
while(c<d)
{
long long sum=nums[a];
sum+=nums[b];
sum+=nums[c];
sum+=nums[d];
if(sum<target)
{
c++;
}
else if(sum>target)
{
d--;
}
else
{
vector<int>v={nums[a],nums[b],nums[c],nums[d]};
//if new quads then push to main vector
if(find(ans.begin(),ans.end(),v)==ans.end())
{
ans.push_back(v);
}
c++;
d--;
}
}
}
}
return ans;
}
};Пояснение:
1. vector<vector<int>> fourSum(vector<int>& nums, int target):
- Это основная функция, которая принимает вектор nums и целевое значение target.
- Она возвращает вектор всех найденных четверок элементов.
2. Инициализация:
- Получаем размер вектора nums и сохраняем его в n.
- Создаем вектор ans, который будет хранить все найденные четверки.
- Сортируем вектор nums в порядке возрастания.
3. Основной цикл:
- Внешний цикл for перебирает все возможные значения a (от 0 до n-1).
- Внутренний цикл for перебирает все возможные значения b (от a+1 до n-1).
- Затем в цикле while мы используем два указателя c и d, которые двигаются навстречу друг другу.
4. Логика поиска:
- Вычисляем сумму текущей четверки (a, b, c, d) и сравниваем ее с target.
- Если сумма меньше target, увеличиваем c, чтобы увеличить сумму.
- Если сумма больше target, уменьшаем d, чтобы уменьшить сумму.
- Если сумма равна target, добавляем текущую четверку в ans, но только если она еще не была добавлена. Для этого мы используем стандартную функцию find() для проверки, есть ли такая четверка в ans.
- После этого увеличиваем c и уменьшаем d, чтобы найти следующую четверку.
5. Возвращаем ans:
- После завершения всех циклов возвращаем вектор ans, содержащий все найденные четверки.
👍1
Задача: №19. Remove Nth Node From End of List #medium
Условие:
Решение:
Пояснение:
1: Инициализация
* Создаем два указателя, slow и fast, оба указывающие на первый узел списка.* Создаем фиктивный узел prev и указываем его на первый узел списка. Это упрощает обработку краевых случаев.
* Указатель answer указывает на фиктивный узел prev.
2: Перемещение указателя fast
* Цикл while перемещает указатель fast на n позиций вперед. Это устанавливает fast на n-й узел от начала списка.
3: Перемещение указателей slow и prev
* Другой цикл while перемещает указатели slow и prev вперед, пока fast не достигнет конца списка. На этом этапе slow будет указывать на узел, предшествующий узлу, который нужно удалить, а prev - на узел перед ним. 4: Удаление узла
* Обновляем prev->next, чтобы пропустить узел, на который указывает slow. Это эффективно удаляет узел из списка.
* Возвращаем answer->next, который указывает на первый узел обновленного списка. Фиктивный узел был добавлен в начале для упрощения обработки.
Условие:
Учитывая заголовок связанного списка, удалите n-й узел из конца списка и верните его заголовок.
Решение:
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* removeNthFromEnd(ListNode* head, int n) {
ListNode *slow, *fast;
slow=head;
fast=head;
ListNode *prev=new ListNode(0,head);
ListNode *answer=prev;
while(n>1){
fast=fast->next;
n--;
}
while(fast->next){
fast=fast->next;
slow=slow->next;
prev=prev->next;
}
prev->next=slow->next;
return answer->next;
}
};
Пояснение:
1: Инициализация
* Создаем два указателя, slow и fast, оба указывающие на первый узел списка.* Создаем фиктивный узел prev и указываем его на первый узел списка. Это упрощает обработку краевых случаев.
* Указатель answer указывает на фиктивный узел prev.
2: Перемещение указателя fast
* Цикл while перемещает указатель fast на n позиций вперед. Это устанавливает fast на n-й узел от начала списка.
3: Перемещение указателей slow и prev
* Другой цикл while перемещает указатели slow и prev вперед, пока fast не достигнет конца списка. На этом этапе slow будет указывать на узел, предшествующий узлу, который нужно удалить, а prev - на узел перед ним. 4: Удаление узла
* Обновляем prev->next, чтобы пропустить узел, на который указывает slow. Это эффективно удаляет узел из списка.
* Возвращаем answer->next, который указывает на первый узел обновленного списка. Фиктивный узел был добавлен в начале для упрощения обработки.
Задача: №20. Valid Parentheses #easy
Условие:
Решение:
Пояснение:
1: Инициализация
* Создаем пустой стек st для хранения открывающих скобок.
2: Итерация по строке
* Перебираем каждый символ c в строке s.
3: Обработка открывающих скобок
* Если символ c является открывающей скобкой (', {' или [', мы помещаем его в стек.
4: Обработка закрывающих скобок
* Если символ c является закрывающей скобкой ')', }' или ], мы проверяем: * Если стек пуст (нет открывающей скобки для пары), или
* Закрывающая скобка не соответствует ожидаемой открывающей скобке в верхней части стека, то * Возвращаем false, поскольку строка не является допустимой.
* Если все проверки пройдены, мы извлекаем соответствующую открывающую скобку из стека.
5: Проверка пустого стека
* После обработки всех символов в строке, если стек пуст, это означает, что все открывающие скобки были сопоставлены с соответствующими закрывающими скобками. В этом случае возвращаем true.
* Если стек не пуст, это означает, что остались несопоставленные открывающие скобки, поэтому возвращаем false.
Условие:
Учитывая строку s, содержащую только символы '(', ')', '{', '}', '[' и ']', определите, является ли входная строка допустимой. Входная строка действительна, если: Открытые скобки должны закрываться скобками того же типа.
Открытые скобки должны закрываться в правильном порядке.Каждой закрывающей скобке соответствует открытая скобка того же типа.
Решение:
class Solution {
public:
bool isValid(string s) {
stack<char> st; // create an empty stack to store opening brackets
for (char c : s) { // loop through each character in the string
if (c == '(' c == '{' c == '[') { // if the character is an opening bracket
st.push(c); // push it onto the stack
} else { // if the character is a closing bracket
if (st.empty() // if the stack is empty or
(c == ')' && st.top() != '(') // the closing bracket doesn't match the corresponding opening bracket at the top of the stack
(c == '}' && st.top() != '{') ||
(c == ']' && st.top() != '[')) {
return false; // the string is not valid, so return false
}
st.pop(); // otherwise, pop the opening bracket from the stack
}
}
return st.empty(); // if the stack is empty, all opening brackets have been matched with their corresponding closing brackets,
// so the string is valid, otherwise, there are unmatched opening brackets, so return false
}
};Пояснение:
1: Инициализация
* Создаем пустой стек st для хранения открывающих скобок.
2: Итерация по строке
* Перебираем каждый символ c в строке s.
3: Обработка открывающих скобок
* Если символ c является открывающей скобкой (', {' или [', мы помещаем его в стек.
4: Обработка закрывающих скобок
* Если символ c является закрывающей скобкой ')', }' или ], мы проверяем: * Если стек пуст (нет открывающей скобки для пары), или
* Закрывающая скобка не соответствует ожидаемой открывающей скобке в верхней части стека, то * Возвращаем false, поскольку строка не является допустимой.
* Если все проверки пройдены, мы извлекаем соответствующую открывающую скобку из стека.
5: Проверка пустого стека
* После обработки всех символов в строке, если стек пуст, это означает, что все открывающие скобки были сопоставлены с соответствующими закрывающими скобками. В этом случае возвращаем true.
* Если стек не пуст, это означает, что остались несопоставленные открывающие скобки, поэтому возвращаем false.
💊1