目录
leetcode783 二叉搜索树最小距离
暴力无脑解法,中序遍历二叉树得到递增数组,比较相邻两个差值与最小值,更新最小值即可
class Solution {
public:
vector<int> num;
int min=1e5;
void helper(TreeNode* root){
if(root==NULL) return ;
helper(root->left);
if(root!=NULL) num.push_back(root->val);
helper(root->right);
}
int minDiffInBST(TreeNode* root) {
helper(root);
for(int i=0;i<num.size()-1;i++){
if(num[i+1]-num[i]<min) min=num[i+1]-num[i];
}
return min;
}
};
leetcode28 实现 strStr() (KMP)
方法一:直接调库,STLfind函数直接返回子串位置
class Solution {
public:
int strStr(string haystack, string needle) {
return haystack.find(needle);
}
};
方法二:KMP
KMP 算法是一个快速查找匹配串的算法,它的作用其实就是本题问题:如何快速在「原字符串」中找到「匹配字符串」。
上述的朴素解法,不考虑剪枝的话复杂度是 O(m∗n) 的,而 KMP 算法的复杂度为 O(m+n)。KMP 之所以能够在 O(m+n) 复杂度内完成查找,是因为其能在「非完全匹配」的过程中提取到有效信息进行复用,以减少「重复匹配」的消耗。
总体下来有点难理解。
核心思路就是构造一个next数组用来保存目标串的每一个字符之前(包括他)的最长相同前后缀。例如aa,前缀1后缀1,那么在next数组1的位置就保存1,表示在这个之前有一个公共前后缀,再例如aabaa,aa是最长公共前后缀,那么在next[4]的位置存放2,代表他前面的子串最长前后缀长度是2。之后和常规的算法相似,扫描到第一个不一样的地方时,常规算法就是倒退,从原字符串第二个开始扫;但KMP不倒退,它会从模版串向后找next[j-1]的位置,代表向后退公共最长前后缀长度,假如在aabaabaaf中找aabaaf。找到b的位置了,不是f,那么说明至少在模版串中,aa是一定有的,因此找f前一位的next数组为2。然后继续往后看,b和b匹配,aaf匹配,结束。
class Solution {
public:
void getNext(int* next, const string& s) {
int j = 0;
next[0] = 0;//初始化第一个为0.
for(int i = 1; i < s.size(); i++) {//从第二个开始遍历模版串s
while (j > 0 && s[i] != s[j]) {//处理前后不一样的情况,首先j一定是>0的,不考虑等于0的情况,因为可能会越界了,而且等于0时考虑一不一样没意义。i代表
j = next[j - 1];//如果前后不一致,就让j回退,退到相同为止。因为这个索引不仅代表数量还代表位置
}
if (s[i] == s[j]) {
j++;//相同的话,就让数量增加,同时往后移。因为设想前面一个既然和后面相等了那么之后需要看后面一个就能判断一共几个相等了
}
next[i] = j;//赋值
}
}
int strStr(string haystack, string needle) {
if (needle.size() == 0) {//base
return 0;
}
int next[needle.size()];//创建一个和needle一样大的数组
getNext(next, needle);//预处理好
int j = 0;
for (int i = 0; i < haystack.size(); i++) {//开始遍历
while(j > 0 && haystack[i] != needle[j]) {//到后面过了第一个还不想等的话,回退,让needle的索引指针回退到next的对应位置。
j = next[j - 1];
}
if (haystack[i] == needle[j]) {
j++;
}
if (j == needle.size() ) {//把后面的needle遍历完了说明找到了一个完整的,返回i路程减掉needle加一就是位置了
return (i - needle.size() + 1);
}
}
return -1;
}
};
leetcode897 递增顺序搜索树
class Solution {
public:
TreeNode *dummy=new TreeNode();//设置一个空头
TreeNode* increasingBST(TreeNode* root) {
TreeNode* tmp=dummy;//别忘了指回去
Traverse(root);
return tmp->right;
}
void Traverse(TreeNode* root){//遍历
if(root==NULL) return ;//
Traverse(root->left);//遍历左边
TreeNode *tmp=new TreeNode(root->val);//建立新节点承接上面
dummy->right=tmp;
dummy=dummy->right;//指向下一个
Traverse(root->right);//遍历右
}
};
快排模版题
void quick_sort(int *a,int l,int r){
if(l>=r) return ;
int i=l-1,j=r+1,x=a[(i+j)/2];
while(i<j){
do i++; while(a[i]<x);
do j--; while(a[j]>x);
if(i<j); swap(a[i],a[j]);
}
quick_sort(a,l,j);quick_sort(a,j+1,r);
}
leetcode 1011 在 D 天内送达包裹的能力
想不出来,还是看思想吧。重点在于这个最低运载能力一定在一个区间内,一个是传送带的重量和,另一个是传送带最大值。假设1次送完,那么肯定总和的运载能力才能送完;假设最多次送完,运载能力肯定是要等于里面最大值才可以。所以在这个区间内用贪心,找到最小的能满足时间的运载能力。假如找到一个满足时间的,就看看比他运载能力小的还有没有能同样满足的;类似如果找不到,就放宽一点看看比他大的有没有满足的
class Solution {
public:
int check(vector<int>& weights,int t,int d){
int cnt=0;//看看这种方法可以几天完成
for(int i=0;i<weights.size();){//从0开始遍历这个数组,逐渐累加前面的和,目的是找到在当前运载能力范围内能放的最多的货物
long long int sum=0;
do{
sum+=weights[i];//加起来
if(sum<=t) i++;//如果小于目标运载能力的话,说明这一天还能再放,把下一个加进去
}while(sum<=t&&i<weights.size());//如果超了,说明这一天只能装这么多了,剩下的要明天装
cnt++;//天数++
}
if(cnt<=d) return 1;//如果这种装载方式满足时间要求,return 1,可以找比他小的能不能满足
else return 0;
}
int shipWithinDays(vector<int>& weights, int D) {
int max=weights[0],sum=0;
for(auto i : weights){
if(i>=max) max=i;
sum+=i;
}//找最小最大
int l=max,r=sum;//左和右
while(l<r){//左小于右
int mid=(l+r)/2;
if(check(weights,mid,D)){//找中间的满足不满足条件
r=mid;//如果满足的话,找比他小的可以不可以
}
else l=mid+1;//不可以的话找比他大的看满足吗
}
return l;
}
};
1486. 数组异或操作
class Solution {
public:
int xorOperation(int n, int start) {
int ans = 0;
for (int i = 0; i < n; ++i) {
ans ^= (start + i * 2);//这还有直接算异或就离谱
}
return ans;
}
};
leetcode连续子数组的最大和
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int dp[100010]={0};
dp[0]=nums[0];
for(int i=1;i<nums.size();i++){
dp[i]=max(nums[i],dp[i-1]+nums[i]);//相当于dp数组每个值先初始化成nums[i]的值。想最后一步,如果让数组最大,就让去掉它的部分最大,以此类推。
}
int res=-9999999;
for(int i=0;i<nums.size();i++){
if(dp[i]>res) res=dp[i];
}
return res;
}
};
1190反转括号内的字符串
递归方法:
原来想的方法也是这样就是递归层数太深了需要优化,优化成这样就可以了没必要再单独开一个去存
class Solution {
public:
//思路是递归处理括号里面的字符串,反转就行。保存到一个string里面直接调库
//可以当成一个模版
string helper(string s,int &i){
string ans="";//ans保存最后结果,也保存单次递归中括号里面的字符串
while(i<s.size()){//循环到最后
if(s[i]=='('){//如果是左括号就递归
i++;//跳过这个字符
ans+=helper(s,i); //加上这个括号里面的东西,如果括号里还有括号,就继续递归
}
else if(s[i]==')') {//碰到右括号结束。跳过这个字符。
i++;
reverse(ans.begin(),ans.end());//反转
return ans;//return就可以了,加到后面去
}
else ans+=s[i++];//basecase情况,啥都没有就直接加到后面
}
return ans;
}
string reverseParentheses(string s) {
int i=0;
return helper(s,i);//模版,递归里面的,i是地址直接改数
}
};
leetcode203移除链表元素
对于给定的链表,首先对除了头节点 head 以外的节点进行删除操作,然后判断 head 的节点值是否等于给定的 val。如果 head的节点值等于 val,则 head 需要被删除,因此删除操作后的头节点为 head.next;如果 head的节点值不等于 val,则 head 保留,因此删除操作后的头节点还是 head。上述过程是一个递归的过程。
/**递归方法**/
class Solution {
public:
ListNode* helper(ListNode* head, int val){
if(head==NULL) return NULL;
head->next=helper(head->next,val);
if(head->val==val) {
return head->next;
}
else return head;
}
ListNode* removeElements(ListNode* head, int val) {
return helper(head,val);
}
};
非递归
注意千万别忘了这种带链表的留一个保存头,老是忘
class Solution {
public:
ListNode* removeElements(ListNode* head, int val) {
ListNode *dummy=new ListNode();
ListNode* ans=dummy;//老是忘
while(head!=NULL){
if(head->val!=val)
{
ListNode *t=new ListNode(head->val);
dummy->next=t;
dummy=dummy->next;
}
head=head->next;
}
return ans->next;
}
};