【c/c++算法刷题笔记】—— LeetCode打卡01


【前言】洛谷闯关暂时告一段落,之后会把笔记放上来。这几天参加一个打卡活动,用的LeetCode和AcWing 。一天5题,打卡二十一天。 如果有想要一起小伙伴在下方留言吧~

1 数组中重复的数字

题目描述

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

笔记
  1. 时间复杂度 o(n),额外空间复杂度 o(1)
  2. 在解看似简单的题目时,要考虑更优化的方案。解题思路:因题目说明,所有数字取值范围 0—n-1,所以我们依次把与下标相等的数放在当前下标的位置,若当前位置已经被占用,说明重复了
    初始数组 :
下标0123456
2310253

依次交换:(遍历到第二个 2 时发现冲突)

下标0123456
0123253
  1. 若用 哈希, 与此解时间复杂度一样,额外空间复杂度o(n)
代码
class Solution {
public:
    bool duplicate(int numbers[], int length, int* duplication) {
      //以上是题目给定模板
      for(int i=0;i<length;i++) if(numbers[i]<0||numbers[i]>length-1) return false; //筛选不符合条件的
      for(int i=0;i<length;i++){ 
        while(i != numbers[i]&& numbers[numbers[i]] != numbers[i])
           swap(numbers[i],numbers[numbers[i]]);
        if(i != numbers[i] && numbers[i]==numbers[numbers[i]]) {
          *duplication=numbers[i];
          return true ;
        }
      }
      return false;
    }
};

2 不修改数组找出重复的数字

题目描述

与上题题目一样。
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

笔记
  1. 用 二分思想
/*
二分模板一共有两个,分别适用于不同情况。
算法思路:假设目标值在闭区间[l, r]中, 每次将区间长度缩小一半,当l = r时,我们就找到了目标值。
版本1
当我们将区间[l, r]划分成[l, mid]和[mid + 1, r]时,其更新操作是r = mid或者l = mid + 1;,计算mid时不需要加1。
*/
int bsearch_1(int l, int r)
{
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
    return l;
}
/*版本2
当我们将区间[l, r]划分成[l, mid - 1]和[mid, r]时,其更新操作是r = mid - 1或者l = mid;,此时为了防止死循环,计算mid时需要加1。
*/
int bsearch_2(int l, int r)
{
    while (l < r)
    {
        int mid = l + r + 1 >> 1;
        if (check(mid)) l = mid;
        else r = mid - 1;
    }
    return l;
}

/*作者:yxc
链接:https://www.acwing.com/blog/content/31/
来源:AcWing
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。*/
  1. for (auto x : nums) :迭代容器中所有的元素,x为每个元素的临时名称
    等同于:for (vector<int>::iterator iter = nums.begin(); iter != nums.end(); iter++)
代码
class Solution {
public:
    int duplicate(vector<int>& numbers) {
      int l=1,r=numbers.size()-1;
      while(l<r){
        int mid=l+r >> 1; //[0,mid]和[mid+1,r]两部分
        int s=0;
        for(auto x:numbers) s += x>=l && x<=mid;
        if(s > mid-l+1) r=mid;
        else l=mid+1;
      }
      return r;
    }
};

3 二维数组中的查找

题目描述

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

样例

输入数组:

[
[1,2,8,9],
[2,4,9,12],
[4,7,10,13],
[6,8,11,15]
]

如果输入查找数值为7,则返回true,
如果输入查找数值为5,则返回false。

笔记
  1. vector 二维数组获取长度:
    int i = a.size()-1; // 行数
    int j = a[0].size()-1; // 列数
  2. 算法思想:由题可知,二维数组每行从左到右递增,每列从上到下递减,类似于二分思想,找到一个中间数 mid,即右上角的数,当 target > mid 时,直接找下一行;当 target < mid 时,直接找前一列。这样可剪枝,每次都会省去查找一列或一行,最总减小算法复杂度
代码
class Solution {
public:
    bool Find(int target, vector<vector<int> > array) { 
      if(array.empty()||array[0].empty()) return false;
      int i=0,j=array[0].size()-1,n=array.size();
      while(i<n && j>=0){
        // 1 出口
        if(array[i][j]==target) return true;
        if(array[i][j]<target) i++;
        else j--;
      }
      return false;
    }
};

4 从尾到头打印链表

题目描述

输入一个链表,按链表从尾到头的顺序返回一个ArrayList。

笔记
  1. 水题。这道题主要是学会了当题目给出指针时如何利用指针得到数组
class Solution {
public:
    vector<int> printListFromTailToHead(ListNode* head) {
      vector<int> res,ArrayList;
      while(head){
        res.push_back(head->val);
        head = head->next;
      }
      for(int i=res.size()-1;i>=0;i--){
        int temp=res[i];
        ArrayList.push_back(temp);
      }
      return ArrayList;
    }
};

5 重建二叉树

题目描述

输入一棵二叉树前序遍历和中序遍历的结果,请重建该二叉树。
注意:
二叉树中每个节点的值都互不相同;
输入的前序遍历和中序遍历一定合法;

样例

给定:
前序遍历:[3, 9, 20, 15, 7]
中序遍历:[9, 3, 15, 20, 7]

返回:[3, 9, 20, null, null, 15, 7, null, null, null, null]
返回的二叉树如下所示:
3
/
9 20
/
15 7

笔记
  1. 复习了建立二叉树。
  2. 算法思想:无论是前序+中序建树 还是后序+中序建树,都以中序下标为轴划分左右子树,所以将中序下标保存,以便之后确定结点的下标位置。
  3. c++中,null 为整数0;nullptr 为 空指针
  4. C++11 中引入的auto主要有两种用途:自动类型推断和返回值占位。TreeNode* left = dfs(pl+1,pl+k-il,il,k-1); 可替换为auto left = dfs(pl+1,pl+k-il,il,k-1);
  5. 数组可直接porder = pre; inorder = vin;
class Solution {
public:   
	map<int,int> hash; 	//为快速找出 中序遍历中某个数的位置  
    vector<int> porder,inorder; 	//为了方便
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
      porder = pre; inorder = vin;
      for(int i=0;i<inorder.size();i++) hash[inorder[i]]=i;
      return dfs(0,porder.size()-1,0,inorder.size()-1);
    }
    
    TreeNode* dfs(int pl,int pr,int il,int ir){
      if(pl>pr) return nullptr; 				//返回null
      TreeNode*root = new TreeNode(porder[pl]);
      int k = hash[root->val];
      TreeNode* left = dfs(pl+1,pl+k-il,il,k-1);
      TreeNode* right = dfs(pl+k-il+1,pr,k+1,ir);
      root->left = left,root->right=right;
      return root;
    }
};

6 二叉树的下一个节点

题目描述

给定一棵二叉树的其中一个节点,请找出中序遍历序列的下一个节点。
注意:
如果给定的节点是中序遍历序列的最后一个,则返回空节点;
二叉树一定不为空,且给定的节点一定不是空节点;

样例

假定二叉树是:[2, 1, 3, null, null, null, null], 给出的是值等于2的节点。
则应返回值等于3的节点。
解释:该二叉树的结构如下,2的后继节点是3。
给定一棵二叉树的其中一个节点,请找出中序遍历序列的下一个节点。

注意:

如果给定的节点是中序遍历序列的最后一个,则返回空节点;
二叉树一定不为空,且给定的节点一定不是空节点;
样例
假定二叉树是:[2, 1, 3, null, null, null, null], 给出的是值等于2的节点。
则应返回值等于3的节点。

解释:该二叉树的结构如下,2的后继节点是3。
2
/
1 3

代码
/*
struct TreeLinkNode {
    int val;
    struct TreeLinkNode *left;
    struct TreeLinkNode *right;
    struct TreeLinkNode *next;
    TreeLinkNode(int x) :val(x), left(NULL), right(NULL), next(NULL) {
       
    }
};
*/
class Solution {
pNodeublic:
    TreeLinkNode* GetNext(TreeLinkNode* pNodeNode)
    {
    	// 1 有右孩子:右孩子
    	if(pNode->right){
    		pNode=pNode->right;
    		while(pNode->left) pNode=pNode->left;
    		return pNode;
	}
	// 2 无右孩子:while(pop()),top()为其父亲的左孩子 —— 下一个结点父亲;top()为其父亲的右孩子,继续出栈  				
	while(pNode->next&&pNode==pNode->next->right) pNode=pNode->next;
	return pNode->next;
    }
};

7 用两个栈实现队列

题目描述

请用栈实现一个队列,支持如下四种操作:
push(x) – 将元素x插到队尾;
pop() – 将队首的元素弹出,并返回该元素;
peek() – 返回队首元素;
empty() – 返回队列是否为空;
注意:

你只能使用栈的标准操作:push to top,peek/pop from top, size 和 is empty;
如果你选择的编程语言没有栈的标准库,你可以使用list或者deque等模拟栈的操作;
输入数据保证合法,例如,在队列为空时,不会进行pop或者peek等操作;

样例

MyQueue queue = new MyQueue();

queue.push(1);
queue.push(2);
queue.peek(); // returns 1
queue.pop(); // returns 1
queue.empty(); // returns false

笔记
  1. stack 可用 size() 函数
代码
class MyQueue {
public:
    /** Initialize your data structure here. */
    stack<int> s,cache;
    MyQueue() {
        
    }
    
    /** Push element x to the back of queue. */
    void push(int x) {
        s.push(x);
    }
    void copy(stack<int> &a,stack<int> &b){
	  while(!a.size()){
        	b.push(a.top());
        	a.pop();
	  }
    }
    /** Removes the element from in front of queue and returns that element. */
    int pop() {
    	  int temp;
        copy(s,cacae);
	  int ans=cache.top(); cache.pop();
	  copy(cache,s);
	  return ans;
    }
    
    /** Get the front element. */
    int peek() {
        int temp;
        copy(s,cacae);
	  int ans=cache.top();
	  copy(cache,s);
	  return ans;
    }
    
    /** Returns whether the queue is empty. */
    bool empty() {
        return s.empty();
    }
};

/**
 1. Your MyQueue object will be instantiated and called as such:
 2. MyQueue obj = MyQueue();
 3. obj.push(x);
 4. int param_2 = obj.pop();
 5. int param_3 = obj.peek();
 6. bool param_4 = obj.empty();
 */

8 斐波那契数列

题目描述

f [n] = f [n-1] + f [n-2]
输入一个整数 n ,求斐波那契数列的第 n 项。
假定从0开始,第0项为0。(n<=39)

笔记
  1. 斐波那契的扩展,分享 :求解 斐波那契 的若干方法 https://www.acwing.com/blog/content/25/
代码
class Solution {
public:
    int Fibonacci(int n) {
        int a=0,b=1,c;
        while(n--){
            c=a+b;
            a=b;
            b=c;
        }
        return a;
    }
};
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值