缺失的第一个正整数
class Solution {
public:
int minNumberDisappeared(vector<int>& nums) {
int n = nums.size();
for(int i=0;i<n;++i){
while(nums[i]>0 && nums[i]<=n && nums[i]!=i+1){
swap(nums[i],nums[nums[i]-1]);
}
}
for(int i=0;i<n;++i){
if(nums[i]!=i+1) return i+1;
}
return n+1;
}
};
两个只出现一次的数
vector<int> FindNumsAppearOnce(vector<int>& array) {
// write code here
int sum=array[0];
for(int i=1;i<array.size();i++)
{
sum=sum^array[i];
}
int sp=1;
while((sp&sum)==0){
sp <<=1;
}
int a=0;
int b=0;
for(int i=0;i<array.size();i++)
{
if((array[i] & sp)==0){
a ^=array[i];
}else{
b ^=array[i];
}
}
if(a<=b){
return {a,b};
}else{
return {b,a};
}
}
右边比当前小的数
class Solution:
def countSmaller(self, nums: List[int]) -> List[int]:
import bisect
queue = []
res = []
for num in nums[::-1]:
loc = bisect.bisect_left(queue, num)
res.append(loc)
queue.insert(loc, num)
return res[::-1]
class Solution {
struct Node {
shared_ptr<Node> left;
shared_ptr<Node> right;
int val;
int count = 0; // 左子树节点的个数
Node(int val) : val(val) {}
};
public:
vector<int> countSmaller(vector<int>& nums) {
shared_ptr<Node> root;
vector<int> res(nums.size());
for (int i = nums.size() - 1; i >= 0; --i) {
root = insert(root, nums[i], &res, i);
}
return res;
}
shared_ptr<Node> insert(shared_ptr<Node> root, int val, vector<int>* res, int index) {
if (!root) {
return make_shared<Node>(val);
}
auto& r = *res;
if (val <= root->val) {
root->count++;
root->left = insert(root->left, val, res, index);
} else {
r[index] += root->count + 1;
root->right = insert(root->right, val, res, index);
}
return root;
}
};
二分模板
int binarySearch1(vector<int> nums,int target){
int left = 0;
int right = nums.size() - 1;//这个right是可以取到的
while(left <= right){//当left==right,区间[left, right]依然有效,所以用 <=
int mid = left + (right - left) / 2;
if(target < nums[mid]){
right = mid - 1;//下次寻找区间[left, mid - 1]
}else if(target > nums[mid]){
left = mid + 1;//下次寻找区间[mid - 1 , right]
}else if(target == nums[mid]){
return mid;
}
}
return -1;
}
版权声明:本文为优快云博主「meraki」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/meraki/article/details/123739815
归并
int temp[]=new int[arr.length];
//mergeSort(arr,0,arr.length-1,temp);
void mergeSort(int[] arr, int left, int right, int[] temp) {
if (left < right) {
int mid = (left + right) / 2;
mergeSort(arr, left, mid, temp);
mergeSort(arr, mid + 1, right, temp);
merge(arr,left,mid,right,temp);
}
}
void merge(int[] arr, int left, int mid, int right, int[] temp) {
int i = left;
int j = mid+1;
int t = 0;
while (i <= mid & j <= right) {
if (arr[i] <= arr[j]) {
temp[t] = arr[i];//temp[0]=arr[i];
t += 1;//指向temp数组下一位
i += 1;//指向左边下一位arr[i+1]...
}else{
temp[t] = arr[j];//temp[0]=arr[i];
t += 1;//指向temp数组下一位
j += 1;//指向右边边下一位arr[j+1]...
}
}
while( i <= mid){
temp[t] = arr[i];
t += 1;
i += 1;
}
while( j <= right){
temp[t] = arr[j];
t += 1;
j += 1;
}
t = 0;
int tempLeft= left;
while( tempLeft <= right){
arr[tempLeft]=temp[t];
t += 1;//赋值成功后指向temp数组的下标指针t往后移
tempLeft +=1;//84 完成后到57 此时left=2 right = 3 ...
}
}
————————————————
版权声明:本文为优快云博主「一条为归的鱼」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/weixin_45857153/article/details/110474615
二分插排
n=len(nums)
for i in range(n):
left=0
right=len(s)-1
while(left<=right):
mid=(left+right)//2
if(s[mid]>nums[n-i-1]):
right=mid-1
else:
left=mid+1
s.insert(left,nums[n-i-1])
逆序对计数
public:
int reversePairs(vector<int>& nums) {
cnt = 0;
mergeSort(nums,0,nums.size()-1);
return cnt;
}
private:
int cnt; //定义一个计数器,记下每次合并中存在的逆序数
void mergeSort(vector<int>& nums, int l, int r){
if(l>=r) return;
int mid = l+(r-l)/2;
mergeSort(nums,l,mid); //递归左边的子数组
mergeSort(nums,mid+1,r); //递归右边的子数组
merge(nums,l,mid,r); //归并
}
void merge(vector<int>& nums, int l, int mid, int r){
//vector<int> temp(r-l+1); //定义一个临时数组
int temp[r-l+1]; //定义一个数组比vector<int>要快
int i = l; //定义一个指针,指向第一个数组的第一个元素
int j = mid+1; //定义一个指针,指向第二个数组的第一个元素
int pos = 0; //定义一个指针,指向临时数组temp的第一个元素
while(i<=mid && j<=r){
if(nums[i]<=nums[j]) temp[pos++]=nums[i++]; //
else{
temp[pos++]=nums[j++]; //
cnt += mid-i+1; //合并时,当左边大于右边,计算逆序数
}
}
while(i<=mid) temp[pos++]=nums[i++];
while(j<=r) temp[pos++]=nums[j++];
for(int k=0; k<(r-l+1); ++k) nums[l+k]=temp[k];
}
};
ip
while True:
try:
x=input().split(".")
y=input().split(".")
z=input().split(".")
m=[]
n=[]
for i in range (len(x)):
x[i]=int(x[i])
y[i] = int(y[i])
z[i] = int(z[i])
if x[0]!=255 or x[3]!=0 or max(x+y+z)>255 or min(x+y+z)<0:
print("1")
else:
for i in range (len(x)):
x[i]=bin(x[i]).replace("0b","")
y[i] = bin(y[i]).replace("0b","")
z[i] = bin(z[i]).replace("0b","")
m.append(int(x[i],2)&int(y[i],2))
#m[i]=m[i].replace("0b","")
n.append(int(x[i],2)&int(z[i],2))
#n[i] = n[i].replace("0b", "")
if m==n:
print("0")
else:
print("2")
except:
break
出现一次和出现三次
int singleNumber(vector<int>& nums) {
int res=0;
for(int i=31;i>=0;i--)
{
int t=0;
for(int j=0;j<nums.size();j++){
t+=(nums[j]>>i &1)==1?1:0;
}
res=res<<1;
if(t%3==1){
res=res| 1;
}
}
return res;
}
并查集
int find(int x) //查找x的教主
{
while(pre[x] != x) //如果x的上级不是自己(则说明找到的人不是教主)
x = pre[x]; //x继续找他的上级,直到找到教主为止
return x; //教主驾到~~~
}
void join(int x,int y) //我想让虚竹和周芷若做朋友
{
int fx=find(x), fy=find(y); //虚竹的老大是玄慈,芷若MM的老大是灭绝
if(fx != fy) //玄慈和灭绝显然不是同一个人
pre[fx]=fy; //方丈只好委委屈屈地当了师太的手下啦
}
桶排序
def bucktetSort(numList,bucketNum):
if len(numList) == 0 or len(numList) == 1:
return numList
maxNum = max(numList)
minNum = min(numList)
bucketSize = (maxNum - minNum + 1) // bucketNum # 根据桶的数量找到每个桶的范围
buckets = [[] for i in range(bucketNum)]
for i in range(len(numList)): # 将各个数分配到各个桶
buckets[(numList[i] - minNum) // bucketSize].append(numList[i])
for i in range(bucketNum): # 桶内排序,可以使用各种排序方法
buckets[i].sort()
res = []
for i in range(len(buckets)): # 分别将各个桶内的数提出来,压入结果
for j in range(len(buckets[i])):
res.append(buckets[i][j])
return res
最长回文子串
def longestPalindrome(self, s: str) -> str:
res=0
n=len(s)
st=0
dp=[[False]*n for i in range(n)]
i=n-1
while i>=0:
for j in range(i,n):
if s[i]==s[j] and (j-i<=1 or dp[i+1][j-1]):
dp[i][j]=True
if dp[i][j] and j-i+1>res:
res=j-i+1
st=i
i-=1
return s[st:st+res]
三数之和
def threeSum(self, nums: List[int]) -> List[List[int]]:
res=[]
nums.sort()
n=len(nums)
for i in range(n-2):
temp=-nums[i]
if i > 0 and nums[i] == nums[i - 1]:
continue
k=n-1
for j in range(i+1,n):
if j > i + 1 and nums[j] == nums[j - 1]:
continue
while j<k and nums[j]+nums[k]>temp:
k-=1
if j==k: break;
if nums[j]+nums[k]==temp:
res.append([nums[i], nums[j], nums[k]])
return res
矩阵 n次方
public double exp(double a, int exp){
if (exp < 0) return exp(1/a, -exp);
if (exp == 0) return 1;
if (exp == 1) return a;
if (exp % 2 == 0)
return exp(a*a, exp/2);
else
return a * exp(a*a, (exp-1)/2);
}
public long[][] matrixExpMul(long[][] result, int exp){
long[][] tmp= {
{1,0,0},
{0,1,0},
{0,0,1}
};
while (exp > 1) {
if ((exp & 0x1) == 1) {
tmp = matrixMul(result, tmp);
result = matrixMul(result, result);
exp = (exp - 1) / 2;
}else {
result = matrixMul(result, result);
exp = (exp) / 2;
}
}
return matrixMul(result, tmp);
}
kmp
字符串匹配
void getNext(int* next, const string& s) {
int j = 0;
next[0] = 0;
for(int i = 1; i < s.size(); i++) {
while (j > 0 && s[i] != s[j]) {
j = next[j - 1];
}
if (s[i] == s[j]) {
j++;
}
next[i] = j;
}
}
int strStr(string haystack, string needle) {
if (needle.size() == 0) {
return 0;
}
int next[needle.size()];
getNext(next, needle);
int j = 0;
for (int i = 0; i < haystack.size(); i++) {
while(j > 0 && haystack[i] != needle[j]) {
j = next[j - 1];
}
if (haystack[i] == needle[j]) {
j++;
}
if (j == needle.size() ) {
return (i - needle.size() + 1);
}
}
return -1;
}
组合
class Solution {
private:
vector<vector<int>> result; // 存放符合条件结果的集合
vector<int> path; // 用来存放符合条件结果
void backtracking(int n, int k, int startIndex) {
if (path.size() == k) {
result.push_back(path);
return;
}
for (int i = startIndex; i <= n; i++) {
path.push_back(i); // 处理节点
backtracking(n, k, i + 1); // 递归
path.pop_back(); // 回溯,撤销处理的节点
}
}
public:
vector<vector<int>> combine(int n, int k) {
result.clear(); // 可以不写
path.clear(); // 可以不写
backtracking(n, k, 1);
return result;
}
};
子集
class Solution {
private:
vector<vector<int>> result;
vector<int> path;
void backtracking(vector<int>& nums, int startIndex) {
result.push_back(path); // 收集子集,要放在终止添加的上面,否则会漏掉自己
if (startIndex >= nums.size()) { // 终止条件可以不加
return;
}
for (int i = startIndex; i < nums.size(); i++) {
path.push_back(nums[i]);
backtracking(nums, i + 1);
path.pop_back();
}
}
public:
vector<vector<int>> subsets(vector<int>& nums) {
result.clear();
path.clear();
backtracking(nums, 0);
return result;
}
};
排列
class Solution {
public:
vector<vector<int>> result;
vector<int> path;
void backtracking (vector<int>& nums, vector<bool>& used) {
// 此时说明找到了一组
if (path.size() == nums.size()) {
result.push_back(path);
return;
}
for (int i = 0; i < nums.size(); i++) {
if (used[i] == true) continue; // path里已经收录的元素,直接跳过
used[i] = true;
path.push_back(nums[i]);
backtracking(nums, used);
path.pop_back();
used[i] = false;
}
}
vector<vector<int>> permute(vector<int>& nums) {
result.clear();
path.clear();
vector<bool> used(nums.size(), false);
backtracking(nums, used);
return result;
}
};
八皇后
class Solution {
private:
vector<vector<string>> result;
// n 为输入的棋盘大小
// row 是当前递归到棋盘的第几行了
void backtracking(int n, int row, vector<string>& chessboard) {
if (row == n) {
result.push_back(chessboard);
return;
}
for (int col = 0; col < n; col++) {
if (isValid(row, col, chessboard, n)) { // 验证合法就可以放
chessboard[row][col] = 'Q'; // 放置皇后
backtracking(n, row + 1, chessboard);
chessboard[row][col] = '.'; // 回溯,撤销皇后
}
}
}
bool isValid(int row, int col, vector<string>& chessboard, int n) {
// 检查列
for (int i = 0; i < row; i++) { // 这是一个剪枝
if (chessboard[i][col] == 'Q') {
return false;
}
}
// 检查 45度角是否有皇后
for (int i = row - 1, j = col - 1; i >=0 && j >= 0; i--, j--) {
if (chessboard[i][j] == 'Q') {
return false;
}
}
// 检查 135度角是否有皇后
for(int i = row - 1, j = col + 1; i >= 0 && j < n; i--, j++) {
if (chessboard[i][j] == 'Q') {
return false;
}
}
return true;
}
public:
vector<vector<string>> solveNQueens(int n) {
result.clear();
std::vector<std::string> chessboard(n, std::string(n, '.'));
backtracking(n, 0, chessboard);
return result;
}
};
数独
class Solution {
private:
bool backtracking(vector<vector<char>>& board) {
for (int i = 0; i < board.size(); i++) { // 遍历行
for (int j = 0; j < board[0].size(); j++) { // 遍历列
if (board[i][j] != '.') continue;
for (char k = '1'; k <= '9'; k++) { // (i, j) 这个位置放k是否合适
if (isValid(i, j, k, board)) {
board[i][j] = k; // 放置k
if (backtracking(board)) return true; // 如果找到合适一组立刻返回
board[i][j] = '.'; // 回溯,撤销k
}
}
return false; // 9个数都试完了,都不行,那么就返回false
}
}
return true; // 遍历完没有返回false,说明找到了合适棋盘位置了
}
bool isValid(int row, int col, char val, vector<vector<char>>& board) {
for (int i = 0; i < 9; i++) { // 判断行里是否重复
if (board[row][i] == val) {
return false;
}
}
for (int j = 0; j < 9; j++) { // 判断列里是否重复
if (board[j][col] == val) {
return false;
}
}
int startRow = (row / 3) * 3;
int startCol = (col / 3) * 3;
for (int i = startRow; i < startRow + 3; i++) { // 判断9方格里是否重复
for (int j = startCol; j < startCol + 3; j++) {
if (board[i][j] == val ) {
return false;
}
}
}
return true;
}
public:
void solveSudoku(vector<vector<char>>& board) {
backtracking(board);
}
};
二叉搜索树验证
def isValidBST(self, root: Optional[TreeNode]) -> bool:
pre=[]
def isValid(root):
if root==None :
return True
l=isValid(root.left)
if len(pre)!=0 and pre[0]>=root.val:
return False
if len(pre)==0:
pre.append(root.val)
else:
pre[0]=root.val
r=isValid(root.right)
return l and r
return isValid(root)
二叉搜索树删除
def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]:
if not root: return None
if root.val==key:
if not root.left and not root.right: #第二种情况:左右孩子都为空(叶子节点),直接删除节点, 返回NULL为根节点
del root
return None
if not root.left and root.right: #第三种情况:其左孩子为空,右孩子不为空,删除节点,右孩子补位 ,返回右孩子为根节点
tmp = root
root = root.right
del tmp
return root
if root.left and not root.right: #第四种情况:其右孩子为空,左孩子不为空,删除节点,左孩子补位,返回左孩子为根节点
tmp = root
root = root.left
del tmp
return root
else: #第五种情况:左右孩子节点都不为空,则将删除节点的左子树放到删除节点的右子树的最左面节点的左孩子的位置
v = root.right
while v.left:
v = v.left
v.left = root.left
tmp = root
root = root.right
del tmp
return root
elif root.val>key:
root.left= self.deleteNode(root.left,key)
else:
root.right= self.deleteNode(root.right,key)
return root
普通二叉树删除
TreeNode* deleteNode(TreeNode* root, int key) {
if (root == nullptr) return root;
if (root->val == key) {
if (root->right == nullptr) { // 这里第二次操作目标值:最终删除的作用
return root->left;
}
TreeNode *cur = root->right;
while (cur->left) {
cur = cur->left;
}
swap(root->val, cur->val); // 这里第一次操作目标值:交换目标值其右子树最左面节点。
}
root->left = deleteNode(root->left, key);
root->right = deleteNode(root->right, key);
return root;
}
最近公共祖先
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if root==None or root==p or root==q: return root
l=self.lowestCommonAncestor(root.left,p,q)
r=self.lowestCommonAncestor(root.right,p,q)
if l and r: return root
if l and not r:
return l
elif r and not l:
return r
else: return None
二叉搜索最近公共祖先
def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
if root.val > p.val and root.val > q.val:
return self.lowestCommonAncestor(root.left, p, q)
if root.val < p.val and root.val < q.val:
return self.lowestCommonAncestor(root.right, p, q)
return root
二叉搜索插入
def insertIntoBST(self, root: TreeNode, val: int) -> TreeNode:
if root==None:
root=TreeNode(val)
return root
if root.val>val:
root.left=self.insertIntoBST(root.left,val)
if root.val<val:
root.right=self.insertIntoBST(root.right,val)
return root
二叉搜索树区间裁剪
def trimBST(self, root: TreeNode, low: int, high: int) -> TreeNode:
'''
确认递归函数参数以及返回值:返回更新后剪枝后的当前root节点
'''
# Base Case
if not root: return None
# 单层递归逻辑
if root.val < low:
# 若当前root节点小于左界:只考虑其右子树,用于替代更新后的其本身,抛弃其左子树整体
return self.trimBST(root.right, low, high)
if high < root.val:
# 若当前root节点大于右界:只考虑其左子树,用于替代更新后的其本身,抛弃其右子树整体
return self.trimBST(root.left, low, high)
if low <= root.val <= high:
root.left = self.trimBST(root.left, low, high)
root.right = self.trimBST(root.right, low, high)
# 返回更新后的剪枝过的当前节点root
return root
优先排序
c++
auto cmp = [](const pair<string, int>& p1, const pair<string, int> p2) {
return p1.second==p2.second?p1.first<p2.first:p1.second>p2.second;
};
priority_queue<pair<string, int>, vector<pair<string, int>>, decltype(cmp)> min_heap(cmp);
python
from functools import cmp_to_key
from collections import defaultdict
def sort_rule(self,x,y):
a, b = x+y, y+x
if a>b: return 1
elif a<b:return -1
else:
return 0
def minNumber(self, nums: List[int]) -> str:
strs = [str(num) for num in nums]
strs.sort(key=functools.cmp_to_key(self.sort_rule))
堆
heapq.heappush(heap,item):将item的值插入heap中,保持堆的不变性。
heapq.heappop(heap):弹出(即删除)并返回heap的最小的元素,保持堆的不变性。
如果堆为空,则抛出IndexError
heapq.heapify(x) 将list x 转换成堆,原地,线性时间内。
heapq.heappushpop(heap,item):先把item加入到堆中,再pop。
heapq.heapreplace(heap,item):先pop,再把item加入到堆中。
heapq.nlargest(n,iterable,key = None):返回大顶堆序列
heapq.nsmallest(n,iterable,key = None):返回小顶堆序列
自定义
from heapq import *
class Node:
def __init__(self,x,y):
self.x=x
self.y=y
def __lt__(self, other):
if self.x==other.x:
return self.y<other.y
else:
return self.x<other.x
if __name__ == '__main__':
y=[]
temp=Node(2,4)
heappush(y,temp)
temp=Node(1,5)
heappush(y,temp)
temp=Node(1,3)
heappush(y,temp)
temp=Node(3,1)
heappush(y, temp)
while len(y)!=0:
it=heappop(y)
堆排序
def heapify(arr, n, i):
largest = i
l = 2 * i + 1 # left = 2*i + 1
r = 2 * i + 2 # right = 2*i + 2
if l < n and arr[i] < arr[l]:
largest = l
if r < n and arr[largest] < arr[r]:
largest = r
if largest != i:
arr[i],arr[largest] = arr[largest],arr[i] # 交换
heapify(arr, n, largest)
def heapSort(arr):
n = len(arr)
# Build a maxheap.
for i in range(n, -1, -1):
heapify(arr, n, i)
# 一个个交换元素
for i in range(n-1, 0, -1):
arr[i], arr[0] = arr[0], arr[i] # 交换
heapify(arr, i, 0)
最小二乘
作者:努力找工作的菜鸡丁
链接:https://www.nowcoder.com/discuss/464012?order=1&pos=24&page=1
来源:牛客网
vector<int> x = { 1, 2, 3, 4 };
vector<int> y = { 6, 5, 7, 10 };
int n = x.size();
double a = 0, b = 0, lr = 0.001;
while (true)
{
double g_a = 0, g_b = 0;
for (int i = 0; i < n; i++) {
g_a += 2 * x[i] * (a*x[i] + b - y[i]);
g_b += 2 * (a*x[i] + b - y[i]);
}
g_a /= n; g_b /= n;
a = a - lr * g_a;
b = b - lr * g_b;
double loss = 0;
for (int i = 0; i < n; i++) {
loss += pow((a * x[i] + b - y[i]), 2);
}
//loss卡在4.2就降不下去
if (loss < 4.2) break;
}
cout << a << endl;
cout << b << endl;
快排
def quick_sort(l,start,end):
i = start
j = end
# 凡是涉及到递归操作的函数,必须存在一个终止条件
if i > j:
return
stand = l[start] # 基准数值,一轮循环后以这个数为基准分为两部分,前方都比它小,后方都比它大
while i < j:
while i < j and l[j] >= stand:
j -= 1
# 这个小循环从后往前找,找到第一个比stand小的数,停止循环,输出当前的索引值
l[i] = l[j]
# 这里注意,这一次赋值后,列表中会出现两个l[j]的值,而l[i]被替换
while i < j and l[i] <= stand:
i += 1
# 这个小循环从前往后找,找到第一个比stand大的数,停止循环,输出当前索引值
l[j] = l[i]
# 上一步赋值导致的列表中存在两个l[j]值,这一步赋值将后方的l[j]替换为l[i],最终列表中存在两个l[i]
l[i] = stand
quick_sort(l,start,i-1)
quick_sort(l,i+1,end)