题目1

判断一个整数是否是回文数。回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数。

示例 1:


输入: 121 输出: true


示例 2:


输入: -121 输出: false 解释: 从左向右读, 为 -121 。 从右向左读, 为 121- 。因此它不是一个回文数。


示例 3:


输入: 10 输出: false 解释: 从右向左读, 为 01 。因此它不是一个回文数。


进阶:

你能不将整数转为字符串来解决这个问题吗?

思路及代码

上面是用转字符串的办法,下面是用数字直接比的办法。

注意每一轮比完将首尾数字去掉。

class Solution {
public:
    /*
    使用转为字符串的办法
    bool isPalindrome(int x) {
        string s = std::to_string(x);
        for(int i = 0;i < s.size();i++){
            if(s[i] != s[s.size()-i-1]){
                return false;
            }
        }

        return true;
    }
    */

    bool isPalindrome(int x) {
        if(x<0) return false;

        int temp = 1;
        while(x/temp>=10) temp*=10;//x是几位数,就将temp赋值为几位数

        while(x>0){
            int left=x/temp;     //获取x左边的第一位
            int right=x%10;	     //获取x的最后一位
            if(left!=right)return false;   //比较两位是否相同
            x=x%temp/10;		 //核心:将x已比较的第一位和最后一位去掉
            temp/=100;		 //x变化,temp也必须变,以便获取第一位	
        }

        return true;
    }
};

题目2

给定一个正整数数组 nums

找出该数组内乘积小于 k 的连续的子数组的个数。

示例 1:


输入: nums = [10,5,2,6], k = 100 输出: 8 解释: 8个乘积小于100的子数组分别为: [10], [5], [2], [6], [10,5], [5,2], [2,6], [5,2,6]。 需要注意的是 [10,5,2] 并不是乘积小于100的子数组。


说明:

  • 0 < nums.length <= 50000
  • 0 < nums[i] < 1000
  • 0 <= k < 10^6

思路及代码

双指针解法维护一个窗口,来算乘积,如果大了就让左边的右移。

class Solution {
public:
    int numSubarrayProductLessThanK(vector<int>& nums, int k) {
        //j指针不断向后扫,记录当前乘积,当当前乘积大于等于k的时候,i指针向前移动。注意要保证i<=j, 每次跟新的结果是加上j-i+1。

        int res = 0;
        int temp = 1;
        int i=0,j=0;

        for(;j<nums.size();j++){
            temp*=nums[j];
            while(temp>=k && i<=j){
                temp/=nums[i];
                i++;
            }
            res+=j-i+1;
        }
        return res;
    }
};

题目3

给出一个以头节点 head 作为第一个节点的链表。链表中的节点分别编号为:node_1, node_2, node_3, ... 。

每个节点都可能有下一个更大值(next larger value):对于 node_i,如果其 next_larger(node_i) 是 node_j.val,那么就有 j > i 且  node_j.val > node_i.val,而 j 是可能的选项中最小的那个。如果不存在这样的 j,那么下一个更大值为 0 。

返回整数答案数组 answer,其中 answer[i] = next_larger(node_{i+1}) 。

注意:在下面的示例中,诸如 [2,1,5] 这样的输入(不是输出)是链表的序列化表示,其头节点的值为 2,第二个节点值为 1,第三个节点值为 5 。

示例 1:


输入:[2,1,5] 输出:[5,5,0]


示例 2:


输入:[2,7,4,3,5] 输出:[7,0,5,5,0]


示例 3:


输入:[1,7,5,1,9,2,5,1] 输出:[7,9,9,9,0,5,0,0]


提示:

  1. 对于链表中的每个节点,1 <= node.val <= 10^9
  2. 给定列表的长度在 [0, 10000] 范围内

思路及代码

考点是单调栈,也是需要学习的部分。

单调栈就是栈内元素单调递增或者单调递减的栈,单调栈只能在栈顶操作。

为了更好的理解单调栈,则可将单调栈用生活情形模拟实现,例如:

我们借用拿号排队的场景来说明下。现在有很多人在排队买可乐,每个人手里都拿着号,越靠前的人手里的号越小,

但是号不一定是连续的。小明拿了号后并没有去排队,而是跑去约会了。等他回来后,发现队伍已经排得很长了,

他不能直接插入到队伍里,不然人家以为他是来插队的。小明只能跑到队伍最后,挨个询问排队人手里的号,

小明认为号比他大的人都是“插队”的,于是小明就会施魔法把这些人变消失,直到小明找到号比他小的为止。

在上面这个场景里,大家排的队伍就像是单调栈,因为大家手里拿的号是单调递增的。

而小明找自己位置的这个过程就是元素加入单调栈的过程。新加入的元素如果加到栈顶后,

如果栈里的元素不再是单调递增了,那么我们就删除加入前的栈顶元素,

就像小明施魔法把“插队”的人变消失一样。直到新元素加入后,栈依然是单调递增时,我们才把元素加进栈里。

(这样做的目的是“维护”单调栈,是单调栈保持原来的单调性不变)

从数组的角度阐述单调栈的性质:

给定一个包含若干个整数的数组,我们从第 1 个元素开始依次加入单调栈里,并且加入后更新单调栈。

那么单调栈有这样的性质:对于单调递增的栈,如果此时栈顶元素为 b,加入新元素 a 后进行更新时,

如果 a 大于 b,说明 a 在数组里不能再往左扩展了(由于单调栈的单调递增性质,b前面的元素均小于a),

也就是说,如果从 a 在数组中的位置开始往左边遍历,则 a 一定是第一个比 b 大的元素;

如果 a 小于 b,说明在数组里,a 前面至少有一个元素不能扩展到 a 的位置(至少有b元素,因为b的值要大于a,如果此时再加入新的

a,那么单调栈便不再单调,所以元素a此时不能压入栈顶,因为这并不是元素a"应该"在的位置,只有当元素a找到自己的位置时

元素a方能压入栈中,而这样做的前提是不改变单调栈的单调性),也就是对于这些元素来说,a 是其在数组右侧第一个比它小的元素。

单调栈的维护是 O(n) 级的时间复杂度,因为所有元素只会进入栈一次,并且出栈后再也不会进栈了。

单调栈的性质:

1.单调栈里的元素具有单调性

2.元素加入栈前,会在栈顶端把破坏栈单调性的元素都删除

3.使用单调栈可以找到元素向左遍历第一个比他小的元素,也可以找到元素向左遍历第一个比他大的元素。

对于第三条性质的解释(最常用的性质):

对于单调栈的第三条性质,你可能会产生疑问,为什么使用单调栈可以找到元素向左遍历第一个比他大的元素,

而不是最后一个比他大的元素呢?我们可以从单调栈中元素的单调性来解释这个问题,由于单调栈中的元素只能是单调递增或者是单调递减的,所以我们可以分别讨论这两种情况(假设不存在两个相同的元素):

1.当单调栈中的元素是单调递增的时候,根据上面我们从数组的角度阐述单调栈的性质的叙述,可以得出:

(1)当a > b 时,则将元素a插入栈顶,新的栈顶则为a

(2)当a < b 时,则将从当前栈顶位置向前查找(边查找,栈顶元素边出栈),直到找到第一个比a小的数,停止查找,将元素a

插入栈顶(在当前找到的数之后,即此时元素a找到了自己的“位置”)

2.当单调栈中的元素是单调递减的时候,则有:
(1)当a < b 时,则将元素a插入栈顶,新的栈顶则为a

(2)当a > b 时,则将从当前栈顶位置向前查找(边查找,栈顶元素边出栈),直到找到第一个比a大的数,停止查找,将元素a

插入栈顶(在当前找到的数之后,即此时元素a找到了自己的“位置”)

---------------------
作者:Adherer

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    vector<int> nextLargerNodes(ListNode* head) {
        vector<int> arr;
        while(head) 
        {
            arr.push_back(head->val);
            head=head->next;
        }

        vector<int> res(arr.size(),0);
        stack<int> stack;

        for (int i = 0; i < arr.size(); ++i)
        {
            while (!stack.empty() && arr[i] > arr[stack.top()])
            {
                int index = stack.top();
                stack.pop();

                res[index] = arr[i];
            }

            stack.push(i);
        }

        return res;
    }
};