一些小结:勉励自己
1.从计划刷题以来,出现了一些方法策略的错误,在朋友的帮助下,慢慢回到正轨,效率up 开心up
2.代码写完要向优秀代码学习,对自己的代码进行优化,比如格式,判断语句如何写更精炼
3.判断,循环类语句注意空格 例:for 🈳️(....)
4.加油,没有翻不过的大山,没有什么是战胜不了的,坚持,成为一种习惯
283.移动零easy
class Solution {
public void moveZeroes(int[] nums) {
int j = 0;
for(int i = 0;i < nums.length;++i){
if(nums[i] != 0){
nums[j] = nums[i];
if (i != j){
nums[i] = 0;
}
j++;
}
}
}
}
11.盛水最多的容器medium
【way 1】嵌套循环遍历
class Solution {
public int maxArea(int[] height) {
int max = 0;
for (int i = 0; i < height.length - 1; ++i){
for (int j = i + 1; j < height.length; ++j){
//int area = _getArea(i,j);
int area = (j - i) * Math.min(height[i], height[j]);
max = Math.max(max, area);
}
}
return max;
}
}
【way 2】左右边界,向中间收敛,O(n)
简称:左右夹逼
class Solution {
public int maxArea(int[] a) {
int max = 0;
for(int i = 0,j = a.length - 1;i < j;){
int minHeight = a[i] < a[j] ? a[i ++] : a[j --];
int area = (j - i + 1) * minHeight;
max = Math.max(max, area);
}
return max;
}
}
70爬楼梯 easy
思想:最近重复子问题
1:1
2:2
3:f(1) + f(2)
4:f(2) + f(3)
:
n:f(n-1)+f(n-2)
本质:Fibonacci数列
class Solution(object):
def climbStairs(self, n):
if(n <= 2): return n
f1,f2,f3 = 1, 2, 3
for i in range(3, n+1):
f3 = f1 + f2
f1 = f2
f2 = f3
return f3
1 两数之和easy
class Solution {
public int[] twoSum(int[] nums, int target) {
for(int i = 0;i < nums.length;i++){
for(int j = i+1;j < nums.length;j++){
if(nums[j] == target - nums[i]){
return new int[]{i,j};
}
}
}
throw new IllegalArgumentException("No two sum solution");
}
}
class Solution {
public int[] twoSum(int[] nums, int target) {
int[] a = new int[2];
int numsSize = nums.length;
for(int i = 0;i < numsSize - 1;i++){
for(int j = i + 1;j < numsSize;j++){
if(nums[i] + nums[j] == target){
a[0] = i;
a[1] = j;
return a;
}
}
}
return new int[0];
}
}
15 三数之和-med-高频老题
双指针法-首先排序
空间复杂度 O(1):指针使用常数大小的额外空间
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
//a + b = -c
//1.暴力求解O(n ^ 3)
//2.hash表
//3.双指针,左右下标往中间推进
Arrays.sort(nums);//排序
List<List<Integer>> res = new ArrayList<>();
for(int k =0; k < nums.length - 2; k++){
if(nums[k] > 0) break;
if(k > 0 && nums[k] == nums[k - 1]) continue;
int i = k + 1, j = nums.length - 1;
while(i < j){
int sum = nums[i] + nums[j] + nums[k];
if(sum < 0){
while(i < j && nums[i] == nums[++i]);
}
else if(sum > 0){
while(i < j && nums[j] == nums[--j]);
}
else{
res.add(new ArrayList<Integer>(Arrays.asList(nums[k], nums[i], nums[j])));
while(i < j && nums[i] == nums[++i]);
/*while(i < j){
i = i + 1;
if(nums[i -1] == nums[i]){
//do sth
}
}*/
while(i < j && nums[j] == nums[--j]);
}
}
}
return res;
}
}
141.环形链表easy
class Solution {
public:
bool hasCycle(ListNode *head) {
//int pos = -1;
//快慢指针,也可用哈希表(目前未实现)
ListNode* slow = head;
ListNode* fast= head;
if(!head || !head->next) return nullptr;
while(fast && fast -> next ){
slow = slow -> next;
fast = fast -> next -> next;
if(fast == slow){
return true;
}
}
return false;
}
};
142.环形链表2 MED
class Solution {
public:
ListNode *detectCycle(ListNode *head) {
ListNode* fast = head;
ListNode* slow = head;
while(fast != NULL && fast -> next != NULL){
slow = slow -> next;
fast = fast -> next -> next;
//快慢指针相遇,确认环的入口点,思路还需再思考
if(slow == fast){
ListNode* index1 = fast;
ListNode* index2 = head;
while(index1 != index2){
index1 = index1 -> next;
index2 = index2 -> next;
}
return index2;
}
}
return NULL;
}
};
25.K个一组翻转链表-hard
【way1 原地翻转】
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
//原地翻转链表
ListNode* dummyhead = new ListNode(-1);
dummyhead -> next = head;
ListNode* starts = head;//记录移动的后面一个指针
ListNode* ends = head;//每次需要翻转的第k个指针
ListNode* pre = dummyhead;//记录当前的头指针
ListNode* nexts,*cur;//cur 记录当前要移动的指针
//链表翻转
while(1){
for (int i = 0; i < k - 1; i++){
if (ends == NULL){
break;
}
ends = ends -> next;
}
if(ends == NULL){
break;
}
nexts = ends -> next;
//原地翻转
for(int i = 0; i < k - 1;i ++){
cur = starts;
starts = starts -> next;
pre -> next = starts;
cur -> next = ends -> next;
ends -> next = cur;
}
starts = nexts;
ends = nexts;
for(int i = 0; i < k;i++){
pre = pre -> next;
}
}
return dummyhead -> next;
}
};
【way2 头插法】
class Solution {
public:
ListNode* reverseKGroup(ListNode* head, int k) {
ListNode* dummynode = new ListNode(-1);
ListNode* current = head;
ListNode* starts = head;
ListNode* nexts = starts -> next;
ListNode* pre = dummynode;
pre -> next = NULL;
while(1){
for(int i = 0;i < k -1; i++){
if(current == NULL){
break;
}
current = current -> next;
}
if(current == NULL){
break;
}
for(int i = 0; i < k; i++){
nexts = starts -> next;
starts -> next = pre -> next;
pre -> next = starts;
starts = nexts;
}
//头插前k个指针
for(int i = 0; i < k;i++){
pre = pre -> next;
}
current = nexts;
}
while(starts){
pre -> next = starts;
pre = pre -> next;
starts = starts -> next;
}
pre -> next = NULL;
return dummynode -> next;
}
};
21.合并两个有序链表
【way 1 递归】
class Solution {
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
//注意题意,l1 和 l2 都是升序的
if(l1 == nullptr ){
return l2;
} else if (l2 == nullptr){
return l1;
} else if(l1 -> val < l2 -> val ){
l1 -> next = mergeTwoLists(l1 -> next,l2);
return l1;
} else{
l2 -> next = mergeTwoLists(l1,l2 -> next);
return l2;
}
}
};
【way 2 迭代】
public:
ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) {
//迭代
ListNode* preHead = new ListNode(-1);//哨兵节点
ListNode* prev = preHead;//全程借助prev 不断调整prev指针的next
while (l1 != nullptr && l2 != nullptr){
if (l1 -> val < l2 -> val){
prev -> next = l1;
l1 = l1 -> next;
} else {
prev -> next = l2;
l2 = l2 -> next;
}
prev = prev -> next;
}
//合并剩余的
prev -> next = l1 == nullptr ? l2 : l1;
return preHead -> next;
}
};
88.合并两个有序数组Easy🤔
class Solution {
public:
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
int i = nums1.size() - 1;
m --;
n --;
while(n >= 0){
while (m >= 0 && nums1[m] > nums2[n]){
swap(nums1[i --],nums1[m --]);
}
swap(nums1[i--],nums2[n--]);
}
}
};
二叉树遍历思路-递归方法,未主动维护一个栈
使用一个存放结果的动态数组res 存放结果
子函数实现递归调用
94.二叉树的中序遍历
class Solution {
public:
//递归,未主动维护一个栈
void mid_order(TreeNode* root,vector<int>& res){
if(root == NULL){
return;
}
mid_order(root -> left,res);
res.push_back(root -> val);
mid_order(root -> right,res);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
if(!root) return res;
mid_order(root,res);
return res;
}
};
144.二叉树的前序遍历
class Solution {
public:
void pre_order(TreeNode* root,vector<int>& res){
if(root == NULL) return;
res.push_back(root -> val);
pre_order(root -> left,res);
pre_order(root -> right,res);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
if(!root) return res;
pre_order(root,res);
return res;
}
};
590.n叉树的后序遍历
class Solution {
public:
vector<int> res;
void order(Node* root){
Node* tmp;
for(int i = 0;i < root -> children.size();i++){
tmp = root -> children[i];
order(tmp);
}
res.push_back(root -> val);
}
vector<int> postorder(Node* root) {
//vector<int> res;
if(!root) return res;
order(root);
return res;
}
};
589.n叉树的前序遍历
class Solution {
public:
vector<int> res;
void order(Node* root){
Node* tmp;
res.push_back(root -> val);
for(int i = 0;i < root -> children.size();i++){
tmp = root -> children[i];
order(tmp);
}
}
vector<int> preorder(Node* root) {
if(!root) return res;
order(root);
return res;
}
};
70.爬楼梯
#找 最近 重复子问题
#if else
# for while recursion
#只有两种可能性:走一步或者走两步
#1: 1
#2: 2
#3: f(1)+ f(2),mutual exclusive,complete exhaustive
#4: f(2)+ f(3)
#f(n) = f(n-1) + f(n-2):Fibonnacci
class Solution(object):
def climbStairs(self, n):
if(n <= 2): return n
f1,f2,f3 = 1, 2, 3
for i in range(3, n+1):
f3 = f1 + f2
f1 = f2
f2 = f3
return f3
22.括号生成
class Solution {
private List<String> result;
public List<String> generateParenthesis(int n) {
result = new ArrayList<String>();
_generate(0, 0, n, "");
return result;
}
private void _generate(int left, int right, int n, String s) {//java 不要用太多的大写
//terminator
if ( left == n && right == n){
System.out.println(s);
result.add(s);
return ;
}
/*if (level >= max) {
//filter the invalid
// left: 随时加,只要超标 right 必须之前有左括号,且左括号> 右括号
System.out.println(s);
return;
}*/
//process current logic:left, right
/*代码优化
String s1 = s + "(";
String s2 = s + ")";
*/
//drill down
if(left < n){
_generate(left + 1,right, n, s + "(");
}
if(left > right ){
_generate(left, right + 1, n, s + ")");
}
//_generate(level + 1,max, s + "(";
//_generate(level + 1,max, s + "(");
//reverse states
}
}
50.Pow(x , n)
class Solution {
public:
double subproblem(double x, long long n){
if(n == 0) return 1;
if(n == 1) return x;
double subresult = subproblem(x, n / 2);
if(n % 2 == 1) {
return subresult * subresult * x;
}else{
return subresult * subresult;
}
}
double myPow(double x, int n) {
long long N = n;
if (N < 0){
x = 1 / x;
N = - N;
}
return subproblem(x ,N);
}
};
//听课思路记录
/*
1.暴力
result = 1
for i: 0 -> n{
result *= x
}
O(n)
*/
//2.牛顿迭代法,难
/*3.分治:转换成子问题
template:1.terminator 2.process(spilt your big problem) 3.drill down(subproblems,merge(subresult))4.reverse states
x^n --> 2^10 : 2^5 -> (2^2)*2
pow(x,n):
subproblems: subresult = pow(x,n/2)
log(N)
merge:
if(n % 2 == 1){
// odd
result = subresult * subresult * x;
}else{
// even
result = subresult * subresult;
}
*/
78.子集
class Solution {
public List<List<Integer>> subsets(int[] nums) {
List<List<Integer>> ans = new ArrayList<>();
if(nums == null) { return ans; }
dfs(ans, nums, new ArrayList<Integer>(), 0);
return ans;
}
private void dfs(List<List<Integer>> ans, int[] nums, List<Integer> list, int index) {
// terminator 终结者
if (index == nums.length) {
ans.add(new ArrayList<Integer>(list));
return;
}
dfs(ans, nums, list, index + 1);//not pick the number at this index
list.add(nums[index]);
dfs(ans, nums, list, index + 1);// pick the number at this index
// reverse the current state
list.remove(list.size() - 1);
}
}
【python】
class Solution(object):
def subsets(self, nums):
"""
迭代法
"""
subsets = [[]]
for num in nums:
newsets = [];
for subset in subsets:
new_subset = subset + [num]
newsets.append(new_subset)
subsets.extend(newsets);
return subsets
【python3】
class Solution:
def subsets(self, nums: List[int]) -> List[List[int]]:
res = [[]];
for i in nums:
res = res + [[i] + num for num in res]简写,掌握
return res