LeetCode题解之需要trick的题(一)

669 阅读3分钟

某一些没有固定做法,但就是有点trick的题

6. Z 字形变换

class Solution {
public:
    string convert(string s, int numRows) {
        //每一行是一个string,leetcode走到0行或者n-1行都反向
        if(numRows == 1) return s;
        bool down = false;
        vector<string> rows(numRows);
        int cur = 0;
        for(auto c : s)
        {
            rows[cur] += c;
            if(cur == 0 || cur == numRows - 1) down = !down;
            if(down) cur ++;
            else cur --;
        }
        string res;
        for(auto x : rows) res += x;
        return res; 
    }
};

121. 买卖股票的最佳时机(剑指 Offer 63. 股票的最大利润)

j记录最低点的价值即可,每次用当前的值-min,得到的肯定是当前买入的收益最大值

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int min = INT_MAX,n = prices.size();
        int res = 0;
        for(int i = 0; i < n; i ++)
        {
            if(prices[i] < min) min = prices[i];//每次更新的时候,记录最低点,并且计算假如当前是在最低点买入的
            res = max(res, prices[i] - min);
        }
        return res;
    }
};

128. 最长连续序列

都存到map里,遍历的时候如果是没有被遍历过(map中没有x-1,也就是x带来了新的序列),就一直往后遍历

class Solution {
public:
    int longestConsecutive(vector<int>& nums) {
        unordered_map<int, int> map;
        for(int n : nums) map[n] ++;
        int res = 0;
        for(int x : nums)//看似两重循环,其实只会被查找一次,因为只有它带来了新序列才会遍历后面的,否则不管它
        {
            if(!map.count(x - 1))//不包含前一个,说明是出现的新序列,往后一直找
            {
                int curnum = x;
                int curcnt = 1;
                while(map.count(curnum + 1))//往后一直遍历
                {
                    curnum += 1;
                    curcnt += 1;
                }
                res = max(res, curcnt);
            }
        }
        return res;
    }
};

169. 多数元素(剑指 Offer 39. 数组中出现次数超过一半的数字)

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        //方法二:投票,众数看作1,其他数看作-1,遇到一个众数会抵消一个非众数
        int cnt = 0, candidate;
        for(int i = 0; i < nums.size(); i ++)
        {
            if(cnt == 0) candidate = nums[i];
            if(candidate == nums[i]) cnt ++;
            else cnt --;
        }
        return candidate;
    }
};

剑指 Offer 03. 数组中重复的数字

交换到指定位置:0,n-1

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) 
    {
        for(int i = 0; i < nums.size();)
        {
            if(i != nums[i])
            {
                int t = nums[i];
                if(t == nums[t]) return t;
                else swap(nums[i], nums[t]);
            }
            else i ++;
        }
        return -1;
    }
};

剑指 Offer 61. 扑克牌中的顺子

class Solution {
public:
    bool isStraight(vector<int>& nums) {
        if(nums.empty()) return false;
        sort(nums.begin(), nums.end());//先排序
        int k = 0;
        while(!nums[k]) k ++;//把行首的0去掉
        for(int i = k + 1;i < nums.size(); i ++)
        {
            if(nums[i] == nums[i-1]) return false;//有相同元素
        }
        return nums.back() - nums[k] <= 4;//最大数-非0最小数,因为已经有5个不重复的值
        //肯定不可能超过4
        //[1,4]再补充一个[0]==5就好
        //[1,3]再补充[0]==4,5就好
        //[1,2]不可能,因为最少就有3个数,差值肯定>=2

    }
};

55. 跳跃游戏

class Solution {
public:
    bool canJump(vector<int>& nums) {
        //更新可以到达的最远位置:意思是这个最远位置前的位置都可以到达
        int n = nums.size();
        int max_len = 0;
        for(int i = 0; i < n; i ++)//o(n)
        {
            if(i <= max_len) //i>r的话i位置都到达不了
            {
                max_len = max(max_len, i + nums[i]);//更新最远距离
                if(max_len >= n-1) return true;
            }
        }
        return false;
    }
};

剑指 Offer 45. 把数组排成最小的数

为什么从小到大的顺序就对呢?假设最终答案的最小值是存在逆序的,a>b但是a在b前面:若abXXX XXabXX肯定不对,因为a>b,若aXXXb,设为ayb,则因为这个数是最小的,所以ay<ya,yb<by=>a<y<b,与已知a>b矛盾,所以不存在逆序的

class Solution {
public:
    static bool cmp(int a , int b)
    {
        auto as = to_string(a), bs = to_string(b);
        return as + bs < bs + as;//字符串拼到一起
    }
    string minNumber(vector<int>& nums) {
        sort(nums.begin(), nums.end(),cmp);//自定义的排序
        string res;
        for(auto x : nums) res += to_string(x);
        return res;
    }
};

剑指 Offer 29. 顺时针打印矩阵

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> res;
        int n = matrix.size();
        if(!n) return res;
        int m = matrix[0].size();
        vector<vector<int>> map(n, vector<int> (m, 0));//map记录

        int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};//4个方向
        int s = m * n;
        int t = 0;
        int x = 0, y = 0;
        for(int i = 0; i < s; i ++)
        {
            if(!map[x][y]) {res.push_back(matrix[x][y]); map[x][y] = 1;}
            int a = x, b = y;
            x += dx[t], y += dy[t];
            if(x < 0 || x >= n || y < 0 || y >= m || map[x][y])//遇到转移方向的时候
            {
                t = (t + 1) % 4;
                x = a + dx[t], y = b + dy[t];
            } 
        }
        return res;
    }
};

剑指 Offer 64. 求1+2+…+n

class Solution {
public:
    int sumNums(int n) {
        int res = n;
        n > 0 && (res += sumNums(n-1)); //if(n>0) res += sumNums(n-1);因为&&和||都是先执行前面,前面不满足不会执行后面
        return res;
    }
};

48. 旋转图像

class Solution {
public:
    void rotate(vector<vector<int>>& matrix) {
        if (matrix.empty() || matrix[0].empty()) return;
        int n = matrix.size();
        //先沿正对角线对调
        for (int i = 0; i < n; i ++){
            for (int j = i; j < n; j ++){
                swap(matrix[i][j], matrix[j][i]);
            }
        }
        //再按照竖轴对调
        for (int i = 0; i < n; i ++){
            int l = 0, r = n - 1;
            while (l < r) swap(matrix[i][l ++], matrix[i][r --]);
        }
    }
};

剑指 Offer 62. 圆圈中最后剩下的数字

class Solution {
public:
    int lastRemaining(int n, int m) {
        //约瑟夫环问题
        if(n == 1) return 0;
        return (lastRemaining(n - 1, m) + m) % n;
    }
};

31. 下一个排列

class Solution {
public:
    void nextPermutation(vector<int>& nums) {
        //3步:
        //1.要让变大后的数尽可能小:从右开始找到第一个逆序的数(在有限的排列中,降序是最大值,升序是最小值,所以降序部分是无法改变的,找到第一个升序的地方进行改变)
        //2.a[i]>a[i-1]时,i-1就是要找的位置,把它与右侧开始找的第一个大于它的数a[j]交换,5,6,11,9,7,5,3,1中找到6后与7交换,
        //3.交换后的值11往后肯定是降序的,是最大的,翻转得到最小的
        if(nums.size() == 1 || nums.empty()) return ;//特殊情况
        int n = nums.size();
        int i = n - 1;//注意弄成全局变量
        for(; i >= 1; i --) if(nums[i] > nums[i - 1]) break;//第一步找到升序的
        if(i == 0)  reverse(nums.begin(),nums.end());//如果没有升序说明是最大值,直接返回
        else{
            int tmp = nums[i - 1];//第二步找到比i-1大一点的数
            int j = n - 1;
            for(; j >= 0; j --) if(nums[j] > tmp) break;
            swap(nums[i - 1], nums[j]);
            reverse(nums.begin() + i,nums.end());//第三步翻转
            return ;
        }

    }
};