leetbook常用数据结构做题分析(基础)

前言

小白一枚,在做题的过程中发生了很多好笑的事情,以供一笑…^~^

题组一:数组与字符串

题目一:https://leetcode-cn.com/leetbook/read/array-and-string/yf47s/

  • 在使用accumlate函数的过程中忘记了添加头文件<numeric>
  • 忘记了accumulate函数的第二个参数对应迭代器的值是不参与求和计算的
  • 在调试的过程中忘记vector的初始化是采取{1,2,3}的赋值形式,而非[1,2,3]
  • 第一道leetcode花了我两个小时^~^!,不是算法不过关(其实也不行),而是语法一堆错
  • 其实可以用左边的和等于总和的一半来做,这样总和只要在进循环之前进行一遍即可,而左边的和可以采用累加的方式来进行,这样就不用用accumulate,时间复杂度从n方降到n
  • vector支持随机访问,这样可以不用迭代器,用下标来替代,(操作已有的元素可以用下标,插入新元素不可以用下标)
class Solution {
public:
    int pivotIndex(vector<int>& nums) {
        if (accumulate(nums.begin()+1, nums.end(), 0) == 0) { return 0; }
        int answer = 1;
        int leftTotal = 0;
        int rightTotal =0;
        for (vector<int>::iterator it = nums.begin()+1; it != nums.end(); ++it) {
            leftTotal = accumulate(nums.begin(), it, 0);
            rightTotal = accumulate(it + 1, nums.end(), 0);
            if (leftTotal == rightTotal) {
                return answer;
            }
            else {
                ++answer;
            }
        }
        return -1;
    }
};

收获:

  • 学会了调试,下面是调试代码,可以更改例子,然后设置断点,逐语句调试的过程中监视关键数据,我就是这样发现leftTotal不对劲的:
    #include <iostream>
    #include<vector>
    #include<numeric>
    
    using namespace std;
    
    class Solution {
    public:
        int pivotIndex(vector<int>& nums) {
            if (accumulate(nums.begin() + 1, nums.end(), 0) == 0) { return 0; }
            int answer = 1;
            int leftTotal = 0;
            int rightTotal = 0;
            for (vector<int>::iterator it = nums.begin() + 1; it != nums.end(); ++it) {
                leftTotal = accumulate(nums.begin(), it, 0);
                rightTotal = accumulate(it + 1, nums.end(), 0);
                if (leftTotal == rightTotal) {
                    return answer;
                }
                else {
                    ++answer;
                }
            }
            return -1;
        }
    };
    int main() {
        vector<int> num = { 1,7,3,6,5,6 };
        Solution example;
        cout<<example.pivotIndex(num);
    }

  • 其实还有很多更好的方法,这个方法只是第一感觉,要多多看看其他人的题解

题目二:https://leetcode-cn.com/leetbook/read/array-and-string/cxqdh/

  • 花了一个小时,好耶!
  • 看到题目的logn和查找,就想到了二分对半查找,算法是知道的,奈何从来没有用C++实现过,所以第一次忽略了很多操作,而且明明记得有个while(left < = right)主体,但是在使用的过程中用不上!所以实操是很重要的!!于是就用了left = mid 和 right = mid来操作了,结果因为这个卡了好久呜呜,测试了很多个案例,后来发现没有考虑到target在两端的特殊情况,我可真是个大聪明啊[]~( ̄▽ ̄)~*,于是加上了开头的判断target与首尾元素大小的判断才通过了测试,对了,在修改的时候,我把其中一种情况的return给误删了,于是就有了下面这段,萌萌的我百度了好久,后来〒▽〒,额。。。调试是个好东西,断点逐语句
  • 做完后看了其他人的解法,我才想起来,原来应该left=mid+1,right=mid-1的呀o(TヘTo),下次一定
class Solution {
public:
    int searchInsert(vector<int>& nums, int target) {
        int left = 0, right = nums.size() - 1;
        if (target <= nums[0]) { return 0; }
        else if (target > nums[right]) { return nums.size(); }
        for (int mid = (left + right) / 2; left < right;) {
            mid = (left + right) / 2;
            if (target == nums[mid]) { return mid; }
            else if (right - left == 1) { return right; }
            else if (target > nums[mid]) {
                left = mid;
            }
            else {
                right = mid;
            }
            mid = (left + right) / 2;
        }

    }
};

题目三:https://leetcode-cn.com/leetbook/read/array-and-string/c5tv3/

  • 题目花了一个半小时,可惜的是二维数组是在下一节才学,刚开始写的时候想过先排序,后来觉得没有这个必要,就直接写了,想法是先创造一个二维数组,再把原数组的一个个插入合并进去,但是再如何插入合并的过程想的太复杂了,分成了判断左右区间落在答案数组的那个区间,反正弄得乱七八糟的,后来忍不住看了眼参考,先排序ε(┬┬﹏┬┬)3,然后就会灰溜溜的回去排序了,后来已看排完序后可以保证前后两个区间的左端点是有序的,问题就变成了,有没有交集,没有直接添加,有交集完不完全包含,包含接下一个,不包含的话改下答案数组的右端点即可 

这是乱七八糟的未完成版

class Solution {

public:

    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        vector<vector<int>> answer;
        while (!intervals.empty()) {
            int left = leftInWhichgroup(intervals, answer);
            int right = rightInWhichgroup(intervals, answer);
            if (left) {
                if (right) {
                    if (right - left == 0) {
                        intervals.erase(intervals.begin());
                    }                    
                }
            }
        }

    }



    int leftInWhichgroup(vector<vector<int>> target, vector<vector<int>> answer) {
        int zu = 1;
        for (vector<vector<int>>::iterator it = answer.begin(); it != answer.end(); ++it,++zu) {
            if ((target[0][0] > (*it)[0]) && (target[0][0] < (*it)[1]))return zu;
        }
        return false;
    }

    int rightInWhichgroup(vector<vector<int>> target, vector<vector<int>> answer) {
        int zu = 1;
        for (vector<vector<int>>::iterator it = answer.begin(); it != answer.end(); ++it, ++zu) {
            if ((target[0][1] > (*it)[0]) && (target[0][1] < (*it)[1]))return zu;
        }
        return false;
    }


};

这是第一次样本通过却超时的版本 

class compare {
public:
    bool operator()(vector<int> &v1, vector<int> &v2) {
        
        return v1[0]<v2[0];      //传入的应该是*it,也就是一个vector<int>
    }                            //这里不能写成if()return true;因为忽略了else的情况
};
static bool cmp(const vector<int>& a, const vector<int>& b) {
    return a[0] < b[0];
}




class Solution {

public:

    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        sort(intervals.begin(), intervals.end(),compare());
        vector<vector<int>>answer;
        int t = 0;
        answer.push_back(intervals[0]);
        while (!intervals.empty()) {
            if (intervals[0][0] > answer[t][1]) {
                answer.push_back(intervals[0]);
                ++t; 
                intervals.erase(intervals.begin()); }//是v1.erase(v1.beigin()) 
            else {
                if(intervals[0][1]>answer[t][1])  //少
                answer[t][1] = intervals[0][1];
                intervals.erase(intervals.begin());
            }
        }
        return answer;
    }
};

我猜测是因为原vector不断地删除头元素,重新配置空间导致的吧,哦还有顺便复习了下sort的用法和谓词的写法,听说直接用静态函数也可以

这是通过版

class Solution {
public:

    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        sort(intervals.begin(), intervals.end());
        vector<vector<int>>answer;
        int t = 0;
        int i =0;
        answer.push_back(intervals[0]);
        while (t!=intervals.size()) {
            if (intervals[t][0] > answer[i][1]) {
                answer.push_back(intervals[t]);
                ++i;
            }
            else {
                if(intervals[t][1]>answer[i][1]){
                answer[i][1] = intervals[t][1];}
            }
            ++t;
 
        }
        return answer;
    }
};

题目四:https://leetcode-cn.com/leetbook/read/array-and-string/clpgd/ 

  • 旋转90度的话大概就是对角线翻转,然后再来水平翻转下了,那就是选对角线的问题了,如果是左对角线(从左上到右下),水平翻转就很简单,直接在一行里reverse(),记住先行后列,如果是右对角线,就要麻烦点,上下翻转的话就涉及到不同的行 

 自己写的版本

class Solution {
public:
    int temp = 0;//注意:vector<vector<int>>temp;不方便  下面的应该是temp[0][0]=matrix[i][j]
    void rotate(vector<vector<int>>& matrix) {
        for (int i = 0; i != matrix.size();++i) {
            for (int j = i; j != matrix[0].size(); ++j) {
                temp = matrix[i][j];     //其实可以用swap
                matrix[i][j] = matrix[j][i];
                matrix[j][i] = temp;
            }
        }
        for (auto i = 0; i != matrix.size(); ++i) {
            reverse(matrix[i].begin(), matrix[i].end());
        }      
    }
};

评论区看到一个更简洁的理想版本,为什莫我就写不出这种风格┭┮﹏┭┮

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        int N = matrix.size();

        //对角线翻转 —— std::swap
        for(int i = 0; i < N; i++)
            for(int j = i + 1; j < N; j++)
                swap(matrix[i][j], matrix[j][i]);

        //水平翻转 —— std::reverse
        for(auto& vec: matrix)
            reverse(vec.begin(), vec.end());
    }
};

作者:TX牧野
链接:https://leetcode-cn.com/leetbook/read/array-and-string/clpgd/?discussion=SR44lT
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

可爱的std

题目五:https://leetcode-cn.com/leetbook/read/array-and-string/ciekh/

  • 题目理解没问题,半个小时过✌,自己的思路就是遍历一遍,记录下为0的(i,j),用二维vector一个个push_back进去就好,然后再实现这个数组涉及的行改0,涉及的列改0,值得注意的是不能一边遍历一边改,因为改完的元素会影响到后面遍历的元素,所以要记录下来,再改,这个思想跟那个py里的生命游戏有点像, 都是记下所有的,再改,不能影响当前状态
  • 看评论里还有一个想法是,不用记录具体位置,只要记录哪行哪列是0即可,然后遍历一遍数组,数组元素里是这些行或者列的改为0即可

下面是我的版本

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        vector<vector<int>> v;
        for (auto i = 0; i != matrix.size();++i) {
            for (auto j = 0; j != matrix[0].size();++j) {
                if (matrix[i][j] == 0) {
                    v.push_back({ i,j });
                }
            }
        }
        for (auto i = 0; i != v.size(); ++i) {
            for (auto row = 0; row != matrix[0].size(); ++row) {
                matrix[v[i][0]][row] = 0;
            }//行上改0
            for (auto col = 0; col != matrix.size();++col) {
                matrix[col][v[i][1]] = 0;
            }//列上改0
        }
    }
};

 题目六:https://leetcode-cn.com/leetbook/read/array-and-string/cuxq3/

罢笔Q了,这题我放弃了,写了好久。。。

题目七:https://leetcode-cn.com/problems/longest-common-prefix/submissions/

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        string answer = "";
        if(strs.empty()||strs[0]=="")return answer;
        if(strs.size()==1){return strs[0];}
        for (int i = 0;; ++i) {
            
            for (int k = 1; k != strs.size(); ++k) {
                if (strs[k][i] != strs[0][i] || i == strs[k].size()) {
                    return answer;
                }
            }
            answer += strs[0][i];
        }
        return answer;
    }
};

 果然还是得面面俱到啊,弄清楚每一轮循环该做什么,同时该层循环该控制的条件,该做的事

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值