2021-03-29 12:08:14    892    0    0

检查是否有摄像头usb设备

使用opencv中的videocapture读取usb摄像头,打开失败,提示索引号不对。打不开usb摄像头时,通常出现的问题是下面这样的错误:

  1. [ WARN:0] global /tmp/pip-req-build-qacpj5ci/opencv/modules/videoio/src/cap_v4l.cpp (893) open VIDEOIO(V4L2:/dev/video0): can't open camera by index

此时可以参考,使用如下命令查看摄像头(也可以直接ls /dev/video*查看。):

  1. v4l2-ctl --list-devices
  1. USB2.0 Camera: USB2.0 Camera (usb-0000:00:14.0-9.4):
  2. /dev/video0
  3. /dev/video1

然后参考,既然不能使用索引打开,那么直接输入尝试看能否打开(没有权限则使用sudo):

  1. import cv2
  2. cap = cv2.VideoCapture('/dev/video0')
  3. ret, frame = cap.read()
  4. print(ret, frame) # 输出False None则说明还是不行

检测是否因为无权限

参考,可能是没有加sudo。基本都是这种情况造成的,特别普遍。

不过加了sudo可能出现ImportError,因为sudo它不是按照通常PATH看到的是一个可执行文件时的顺序,具体参考。因此,手动指定python版本,如下即可:

  1. sudo /home/bobo/anaconda3/envs/pytorch1.4/bin/python manage.py runserver 0.0.0.0:8009

检查是否因为端口占用

1、端口占用,导致摄像头也被占用。有时候使用ctrl+z结束程序就会造成这样的情况。因为尽管ctrl+cctrl+z都是中断命令,但是他们的作用却不一样。ctrl+c是强制中断程序的执行,会释放资源。ctrl+z是将任务中断,但是此任务并没有结束,他仍然在进程中他只是维持挂起的状态,用户可以使用fg/bg

2020-08-04 23:01:03    585    0    0

1.半径为1的圆中随机选取一点

  • 方法1:在x轴[-1,1],y轴[-1,1]的正方形随机选取一点,如果此点在圆内,则即为所求的点。如果不在圆内,则重新随机直到选到了为止。
  • 方法2:从[0, 2*pi)随机选取一个角度,再在这个方向的半径上随机选取一个点。但半径上的点不能均匀选取,选取的概率要和离圆心的距离成正比,这样才能保证随机点在圆内是均匀分布的。

2.一根木棒,截成三截,组成三角形的概率是多少?

  • 设第一段截x,第二段截y,第三段1-x-y
  • 考虑所有可能的截法。可能的截法中必须保证三条边都是正数且小于原来边长,则有0<x<1,0<y<1,0<1-x-y<1,画图可知,(x,y)必须在单位正方形的左下角的半个直角三角形里,面积为1/2。
  • 然后考虑能形成三角形的截法。首先要满足刚才的三个条件0<x<1,0<y<1,0<1-x-y<1,然后必须符合三角形的边的要求,即两边之和大于第三边,x+y>1-x-y,x+1-x-y>y,y+1-x-y>x,化简即得0<x<1/2,0<y<1/2,1/2<x+y<1画图可知,此时(x,y)必须在边长为1/2的三角形的右上角的半个直角三角形里,面积为1/8。于是最终概率为(1/8)/(1/2) = 1/4

3. 抛色子求期望问题

  • 抛一个六面的色子,连续抛直到抛到6为止,问期望的抛的次数是多少
  • 方法1:因为每次抛到6的概率相等,都是1/6,于是期望的次数就是1/(1/6)=6次。
  • 方法2:下面用一种不一样的方法解答,假设期望的次数为E。考虑第一次抛,如果已经抛到6了(概率为1/6),那么就不用再抛了。如果没抛到6(概率为5/6),那么还需要继续抛,可是还要抛多少次呢?显然,现在开始知道抛到6的次数仍然是E,但是刚刚已经抛了一次了于是可以得到这个等式
    E=1×16+(1+E)×56
    解得
2020-07-02 22:57:41    649    0    0

二分查找用于有序或者部分有序的数组查找

收缩可能为空集

  • 如果二分查找最终可能存在查不到的情况(无论是查找点或者区间),则必须这么写。
  • 这是比较万能一点的写法,但缺点是通常需要额外判断left,right的越界情况,以及查找的结果情况。
  1. while(left<=right)
  2. {
  3. mid = (left + right)>>1;
  4. if(...)
  5. {
  6. right = mid -1;
  7. }
  8. else if(...)
  9. {
  10. left = mid + 1;
  11. }
  12. else ...
  13. }
  14. //这里通常需要额外的判断,可以通过left位置的情况,判断是否查找到了target
  15. if(left>=nums.size() || right < 0 || (nums[left]!=target))
  16. {
  17. ...
  18. }
  19. //比如这个题:https://leetcode-cn.com/problems/find-first-and-last-position-of-element-in-sorted-array/

收缩为一个点

  • 这是比较常见的情况,也即最终left和right最终必然会收缩成一点,也有可能存在找不到target的情况,也需要判断。但比前面简单的地方在于,[left,right]不会越出[0,nums.size()-1]的范围,判断条件简单一点:
  1. while(left < right)
  2. {
  3. mid = ...;
  4. if(...)
  5. {
  6. right = mid;
  7. }
  8. else
  9. {
  10. left = mid + 1;
  11. }
  12. }
  13. //跳出循环后,left==right,left或者right都可以是我们需要的结果,只需简单判断一下
  14. if(nums[left]!=target)
  15. {
  16. //说明没找到
  17. }
  18. //比如这个题:https://leetcode-cn.com/problems/search-in-rotated-sorted-array/
  • 因为C++默认的除法特性,即(1+2)/2 == 1这样的原因,像这样写可能造成死循环
2020-06-14 23:00:15    503    0    0

1、线程的创建

  • 头文件#include <pthread.h>
  • 在Linux中,通过函数pthread_create()函数实现线程的创建:
  1. int pthread_create(pthread_t *thread, const pthread_attr_t *attr,void *(*start_routine) (void *), void *arg);
  • pthread_create参数
    • thread表示的是一个pthread_t类型的指针;
    • attr用于指定线程的一些属性;
    • start_routine表示的是一个函数指针,该函数是线程调用函数;传参时,可以用取地址符&函数名,比如&myFunc,当然也可以直接传函数名。
    • arg表示的是传递给线程调用函数的参数。
  • 当线程创建成功时,函数pthread_create()返回0,若返回值不为0则表示创建线程失败。对于线程的属性,则在结构体pthread_attr_t中定义。

  • g++编译运行需要使用-lpthread参数:

  1. g++ test.cpp -lpthread -o test.o

2、线程终止

  • 终止某个线程而不终止整个进程有下面三种方法:
    • 在线程函数中return。这种方法对主线程不适用,从main函数return相当于调用exit。//线程return
    • 线程自己调用pthread_exit来终止自己,主动终止: int pthread_exit(void* retval);,注意:retval不能指向该线程的栈空间,否则可能成为野指针
    • 一个线程调用pthread_cancel来终止另外一个线程,被动终止
  • 终止某个线程并终止所有的线程:
    • 任意线程调用了exit(),或者主线程执行了return语句(即在main()函数中),都会导致进程中的所有线程立即终止。

3、线程等待

  • 当一个线程退出时,如果空间没有被释放,新创建的线程也不会利用退出线程的资源,所以会发生内存泄漏。因此新线程在退出时主线程要通过等待的方式回收退出现成的资源并获取新线程退出时的状态,或者分离也可以安全地释放资源。
  • 一个线程仅允许一个线程使用pthread_join()等待
2020-05-04 21:05:57    53    0    0

1 序

  • 我们通常所说的排序算法往往指的是内部排序算法,即数据记录在内存中进行排序。排序算法大体可分为两种:

1.1 比较排序

时间复杂度O(nlogn) ~ O(n^2),主要有:冒泡排序,选择排序,插入排序,归并排序,堆排序,快速排序等。

1.2 非比较排序

时间复杂度可以达到O(n),主要有:计数排序,基数排序,桶排序等。

1.3 图表

title
这里的排序算法稳定性的简单形式化定义为:如果Ai = Aj,排序前Ai在Aj之前,排序后Ai还在Aj之前,则称这种排序算法是稳定的。通俗地讲就是保证排序前后两个相等的数的相对顺序不变。

对于基础类型,相同值是无差别的,排序前后相同值的相对位置并不重要,所以选择更为高效的快速排序,尽管它是不稳定的排序算法;而对于非基础类型,排序前后相等实例的相对位置不宜改变,所以选择稳定的归并排序。

2 比较排序代码

2.1 冒泡排序

  1. // 分类 -------------- 内部比较排序
  2. // 数据结构 ---------- 数组
  3. // 最差时间复杂度 ---- O(n^2)
  4. // 最优时间复杂度 ---- 如果能在内部循环第一次运行时,使用一个旗标来表示有无需要交换的可能,可以把最优时间复杂度降低到O(n)
  5. // 平均时间复杂度 ---- O(n^2)
  6. // 所需辅助空间 ------ O(1)
  7. // 稳定性 ------------ 稳定
  8. void Swap(int A[], int i, int j)
  9. {
  10. int temp = A[i];
  11. A[i] = A[j];
  12. A[j] = temp;
  13. }
  14. void BubbleSort(int A[], int n)
  15. {
  16. for (int j = 0; j < n - 1; j++) // 每次最大元素就像气泡一样"浮"到数组的最后
  17. {
  18. for (int i = 0; i < n - 1 - j; i++) // 依次比较相邻的两个元素,使较大的那个向后移
  19. {
  20. if (A[i] > A[i + 1]) // 如果条件改成A[i] >=
2020-04-11 16:13:50    44    0    0

7.链表(Linked List)

7.1 环形链表

141. Linked List Cycle

给定一个链表,判断链表中是否有环。

为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始)。 如果 pos 是 -1,则在该链表中没有环。

  1. 示例 1
  2. 输入:head = [3,2,0,-4], pos = 1
  3. 输出:true
  4. 解释:链表中有一个环,其尾部连接到第二个节点。
  5. 示例 2:
  6. 输入:head = [1,2], pos = 0
  7. 输出:true
  8. 解释:链表中有一个环,其尾部连接到第一个节点。
  9. 示例 3
  10. 输入:head = [1], pos = -1
  11. 输出:false
  12. 解释:链表中没有环。
  1. /**
  2. * Definition for singly-linked list.
  3. * struct ListNode {
  4. * int val;
  5. * ListNode *next;
  6. * ListNode(int x) : val(x), next(NULL) {}
  7. * };
  8. */
  9. class Solution {
  10. public:
  11. bool hasCycle(ListNode *head) {
  12. return funcDulPointer(head);
  13. }
  14. //方法一:缓存cache法
  15. bool funcCache(ListNode *head)
  16. {
  17. set<ListNode*> cache;
  18. while(head)
  19. {
  20. if(cache.find(head)!=cache.end()) return true;
  21. else{
  22. cache.insert(head);
  23. }
  24. head = head->next;
  25. }
  26. return false;
  27. }
  28. //方法二:将所有访问过的node的val都设置为一个新的值,以此来判断是否有环。
2020-04-11 16:13:46    40    0    0

4.动态规划(Dynamic Programming)

4.1 买卖股票的最佳时机

(Best Time to Buy and Sell Stock)

I 只能买卖一次:

  • 题目要求
    • 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
    • 如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
    • 注意:你不能在买入股票前卖出股票。
  • 测试样例
  1. - 输入: [7,1,5,3,6,4]
  2. - 输出: 5
  3. - 解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5
  4. 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格。
  • 参考代码
  1. class Solution {
  2. public:
  3. int maxProfit(vector<int>& prices) {
  4. if(prices.size()==0) return 0;
  5. int profit = 0;
  6. int min_price = prices[0];
  7. for(int i = 1;i < prices.size();i++)
  8. {
  9. min_price = min(prices[i-1],min_price); //动态规划最低的价格
  10. profit = max(profit,prices[i] - min_price);
  11. }
  12. return profit;
  13. }
  14. };

II 不限制交易次数:

"有钱就赚",可以交易多次:

  1. class Solution {
  2. public:
  3. int maxProfit(vector<int>& prices) {
  4. int len = prices.size();
  5. if(len == 0) return 0;
  6. int profit = 0;
  7. for(int i = 1;i<len;i++)
2020-04-11 16:13:44    41    0    0

1.数组(Array)

1.2 移除元素(27-th:Remove Element)

  • 题目要求
    • 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
    • 不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并原地 修改输入数组。
    • 元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
  • 测试样例:
  1. - 给定 nums = [3,2,2,3], val = 3,
  2. - 函数应该返回新的长度 2, 并且 nums 中的前两个元素均为 2
  • 你不需要考虑数组中超出新长度后面的元素。
    • 个人参考代码
  1. class Solution {
  2. public:
  3. int removeElement(vector<int>& nums, int val) {
  4. int length =nums.size();
  5. int i=0,j=0;
  6. for(;i<length;i++)
  7. {
  8. if(nums[i]!=val)
  9. {
  10. nums[j] = nums[i];
  11. j++;
  12. }
  13. }
  14. return j;
  15. }
  16. };

1.3.1 删除排序数组中的重复项

(26th:Remove Duplicates from Sorted Array)
- 题目要求
- 给定一个排序数组,你需要在 原地 删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度。

  • 不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

    • 测试样例
  1. 给定 nums = [0,0,1,1,1,2,2,3,3,4],
  2. - 函数应该返回新的长度 5, 并且原数组 nums 的前五个元素被修改为 0, 1, 2, 3, 4
  • 你不需要考虑数组中超出新长度后面的元素。

    • 参考代码
  1. class Solution {
  2. public:
  3. int re
2020-04-01 16:57:16    423    0    0

1.什么是红黑树

  • 红黑树(Red Black Tree)是一种自平衡的二叉查找树,是一种高效的查找树. 它是由 Rudolf Bayer于1978年发明,在当时被称为对称二叉B 树(symmetric binary B-trees)。后来,在1978年被Leo J. GuibasRobert Sedgewick修改为如今的红黑树。
  • 红黑树具有良好的效率,它可在 O(logN) 时间内完成查找,增加,删除等操作.
  • 红黑树在业界应用很广泛,比如 Java中的TreeMap,JDK 1.8中的HashMap,C++ STL 中的mapset 底层均是基于红黑树结构实现的.
  • 虽然红黑树实现很复杂,但考虑到红黑树是一种被广泛应用的数据结构,所以我们很有必要去弄懂.

2.红黑树定义及性质

红黑树(RBT)的定义:它或者是一颗空树,或者是具有一下性质的二叉查找树:

  1. 1.节点非红即黑。
  2. 2.根节点是黑色。
  3. 3.所有NULL结点称为叶子节点,且认为颜色为黑。
  4. 4.所有红节点的子节点都为黑色。
  5. 5.从任一节点到其叶子节点的所有路径上都包含相同数目的黑节点。

红黑树的基本操作和其他树形结构一样,一般都包括查找,插入,删除等操作.红黑树举例:
title

3.旋转操作

旋转操作分为左旋右旋,左旋是将某个节点旋转为其右孩子的左孩子,而右旋是节点旋转为其左孩子的右孩子.看图就很容易明白:
title

4.插入操作

红黑树的插入过程和二叉查找树插入过程基本类似,不同的地方在于,红黑树插入新节点后,需要进行调整,以满足红黑树的性质.为了调整简单,插入节点应该红色的,此时通过变色和旋转调整,使其满足红黑树的所有性质即可.
接下来,将分析插入红色节点后红黑树的调整情况.这里假设要插入的节点为 N,N 的父节点为 P,祖父节点为 G,叔叔节点为 U.插入红色节点后,会出现5种情况,分别如下:

4.1 情况一

  • 插入的新节点 N 是红黑树的根节点,
  • 这种情况下,我们把节点 N 的颜色由红色变为黑色,所有性质满足,结束.

4.2 情况二

  • N 的父节点是黑色,
  • 这种情况下,性质4(每个红色节点必须有两个黑色的子节点)和性质5没有受到影响,不需要调整.
2020-03-12 16:24:02    516    0    0

(一)int与char的转换

实际上char也是采用8位整型存储的,参考:
https://wenda.so.com/q/1467568769728405?src=170&q=C%2B%2B+char%E6%9C%AC%E8%B4%A8

(1)根据ASCLL码转换:

  1. //char转int
  2. char a = '3';
  3. int b = a - '0';
  4. //int转char
  5. char c = b + '0';
  6. char c = b + 48;//48是0的ascll码值

title
(2)强制转换

  1. a = char(b);
  2. b = int(a);

参考地址:
https://blog.csdn.net/qq_30534935/article/details/82683643

(二)string、char *、char[]相互转换

(1)string转char*:

主要有三种方法可以将string转换为char*类型,分别是:data()、c_str()、copy()
其中,copy()可能会报安全性错误,自行解决即可。

  1. string s = "hello";
  2. char *ch1 = s.data();
  3. const char *ch1 = (char*)s.data();
  4. char *ch2 = s.c_str();//实际上就是转为c风格字符串
  5. char ch3[20];
  6. //str.copy(cstr,n,pos);
  7. s.copy(ch3,5,0);
  8. *(p+5) = '\0';//'\0'的意思是 ASCII 为 0 的字符。
  9. 它所的意义是“字符串结束符”。

(2)char*转string

直接赋值即可:

  1. string s;
  2. char *p = "helloworld";
  3. s = p;

(3)string转char[]

for循环遍历输入:

  1. string pp = "helloworld";
  2. char p[20];
  3. int i;
  4. for( i=0;i<pp.length();i++)
  5. p[i] = pp[i];
  6. p[i] = '\0'; //添加结束符

(4)char