leetcode第一刷_Sqrt(x)】的更多相关文章

这道题乍看下来很easy,实际上要注意的问题许多. 注意看给出来的函数的接口,返回的是int值,也就是计算结果是个近似值.如何求呢?难道是从2開始往上算?直到某个值正好接近x?当然不行,肯定超时了.再细致想一下,对了,有二分法,从最大的開始,每次计算一下平方,假设结果比x大,那么缩短上界,否则提高下界. 思想非常正确,以下的问题是最大的那个值是多少?你会毫不犹豫的说出是x啊,x的平方根肯定比x小吧.好,那假设x是INT_MAX呢,你想用什么类型来存储这个平方的结果?并且这样每次减半,也得好一会儿…
这个题乍一看非常easy,实际上还挺有技巧的.我最開始的想法是找一个特殊值标记.遇到一个0,把他所相应的行列中非零的元素标记成这个特殊值.0值保持不变,然后再从头遍历一次,碰到特殊值就转化成0. 问题是这个特殊值怎么确定,题目中没有把取值范围给出,我怀着侥幸的心理用了最大和最小的int,都被揪了出来..假设找一个不存在于数组中的值,这个复杂度太高了. 有没有其它更好的方法呢?当然有.这个思想非常巧妙,最后的结果是把所有0所在的行列都化成0,换句话说.化成0这个事情仅仅要标记出是哪一行以及哪一列就…
当有反复元素的时候呢? 不用拍脑袋都会想到一种方法,也是全部有反复元素时的通用处理方法,维护一个set,假设这个元素没增加过就增加,增加过了的忽略掉.可是,在这道题上这个通用方法竟然超时了! 怎么办?想一下为什么会这样,如果我们要排列的数字是1111112,当当前的排列中没有1时,取哪个1生成一遍,都是一样的.仅仅有当前面的1都用过了,必须轮到这个1出场的时候,它才会有价值.更明白一点说,如果我们要在生成的排列中放两个1,那么这两个1是原来的哪两个根本无所谓,不断的选,终于的结果肯定一样,可是当…
很自然的推广,假设去掉全然二叉树的条件呢?由于这个条件不是关键,因此不会影响整体的思路.做法依旧是每次找到一层的起点,然后一层一层的走. 假设是全然二叉树的话,每层的起点就是上一层起点的左孩子,兄弟之间的链接也简单,直接找相应父亲的左右孩子就可以. 一般二叉树时,起点应该是上一层第一个有孩子节点的左孩子,或者没有左孩子时.是他的右孩子. 为了能在孩子层中不断链接,我们必须保存当孩子层的前一个节点,当当前层找到一个节点有孩子,就接到这个pre节点后面,然后更新pre节点的指向. class Sol…
看到这个题我就伤心啊,去微软面试的时候,第一个面试官让我做的题目就是实现集合的交操作,这个集合中的元素就像这里的interval一样.是一段一段的.当时写的那叫一个慘不忍睹.最后果然被拒掉了. .好好练习算法,争取正式招聘的时候拒一次微软.哈哈~ 说归说,这道题事实上还是比較简单的.先考虑什么样子的集合是能够合并的.设两段集合是[a, b]和[c, d],不失一般性的,如果a<c,那么有以下几种情况: 1. b<c,这说明两段是全然不相交的,没办法合并. 2. b>=c&&…
八皇后问题应该是回溯法的教学典范.在本科的时候,有一门课叫面向对象.最后的附录有这个问题的源码.当时根本不懂编程,照抄下来,执行一下出了结果都非常开心,哎. 皇后们的限制条件是不能同行同列,也不能同对角线. 那么显然每一列上都要有一个皇后,仅仅须要用一个一维数组记录皇后在每一行上的位置就能够了. 算法的思想是:从第一行開始,尝试把皇后放到某一列上,能够用一个vis数组保存已经有皇后的列,当找到一个还没有皇后的列时,就尝试着把当前皇后放上,然后看看有没有之前放好的皇后跟这个皇后同对角线,假设同对角…
说到格雷码,应该没人不知道,详细它有什么用,我还真不是非常清楚,我室友应该是专家.生成的规律不是非常明显,之前看到帖子讲的,这会儿找找不到了.. 思想是这种,假设有n位,在第2^(n-1)个编码以下画一条水平线的话,你会发现除了第一位之外,其它位都是关于这条线对称的,例如以下,以三位格雷码举例: 000 001 011 010 --------------------- 110 111 101 100 非常奇妙吧,我曾经是不知道这个规律的.从一開始的一位格雷码,0,1,開始,每次对称的在上一个前…
啊啊啊啊.好怀念这样的用递归保存路径然后打印出来的题目啊.好久没遇到了. 分了两种,一种是能够反复使用数组中数字的,一种是每一个数字仅仅能用一次的.事实上没有多大差别,第一种每次进入递归的时候都要从头開始尝试.另外一种要找一个标记的数组,把已经用到过的排除掉,就像生成全排列时的做法一样. 跟我一样用引用保存中间结果的话.要注意回退的情况. 另外一种回退时,要把用到的那个数也恢复为可用,就全然像全排列时做的一样.破例贴两个题的代码.由于他们是在是不值得用两片文章来写. class Solution…
水题. 描写叙述的还挺麻烦的,实际上就是纸老虎,用两个string,一个存上一轮的结果,一个用来更新出这一轮的结果,每次扫描上一轮,统计一个字符出现的次数,然后把这个次数和字符增加到这一轮的字符串中就能够了. class Solution { public: string countAndSay(int n) { if(n == 0) return ""; string tpres, res = "1"; for(int i=1;i<n;i++){ int j…
这个题事实上非常easy的,我一開始想复杂了,它没要求记录路径,事实上仅仅要看一下每一步之后所能延伸到的最远的位置就能够了,在这一个最远位置前面的那些位置,都是能够到达的,假设扫到了某个i,它大于当前能延伸到到的最远位置,说明这个i不可达.终于的位置能不能到达,就看终于延伸到的位置能不能大于等于它. class Solution { public: bool canJump(int A[], int n) { if(n == 0) return false; if(n == 1) return…
非常easy的一道DP,看到空间限制是O(N)的,不要习惯性的以为是要保存每一行的最小值,不难想到是要保存一行其中各个数为路径终点时的和的大小.当算到最后一行时,就是从顶部究竟部以这个底部位置为终点的最短路径和,找一个最小的就能够了. 实现的时候要注意个问题,由于计算时要用到上一行的数据,所以为了避免数据被覆盖,应该从后往前算,这个技巧用的非常多,相信大家都非常熟悉. ac代码例如以下: class Solution { public: int minimumTotal(vector<vecto…
有了上面的教训,这道题就简单多了,什么时候该更新pre是明白的了,倒是有个细节,二叉搜索树中是不同意有相等节点的,所以题目的要求用黑体字标明了.写的时候注意就能够了. class Solution { public: TreeNode *pre = NULL; bool isValidBST(TreeNode *root) { if(root == NULL) return true; bool res = true; if(root->left) res &= isValidBST(roo…
有关这样的字符串的题真是层出不穷啊,并且他们都有这样一个特点,就是递归的思路如此简单,但一定超时! 这个时候,dp就朝我们缓缓走来.递归超,dp搞!这道题的状态转移方程还是比較好写的,用ispart[i][j]代表s1贡献i长,s2贡献j长时,能不能形成s3的前i+j个字符.更新能够依照行或者列開始,s3的前i+j个字符,能够是((i-1)+1)+j构成,也能够是i+((j-1)+1)构成,这取决于当前的这个字符s3[i+j-1]跟s1[i-1]和s2[j-1]是否相等,或的关系就能够解决这个问…
构造方式跟中序与后序全然一样,并且一般都习惯正着来,所以更简单. 代码是之前写的,没实用库函数,不应该. TreeNode *buildIt(vector<int> &preorder, int start1, vector<int> &inorder, int start2, int len){ if(len <= 0) return NULL; TreeNode *root = new TreeNode(preorder[start1]); int i =…
这道题非常难. 之前的题目我提到过一次用两个vector来做层序遍历的,就是由于这道题.要想最后恢复出单词变换的路径,就须要事先保存,依据dp中路径恢复的启示,保存的应该是一个单词的前一个变换节点.可能有非常多个单词都能变换到当前单词,因此应该是一个set.用一个二维的vector保存当前能够变换到的单词和变换出这些单词单词.每一维的vector存放的都是一个set.设存放当前可訪问单词的vector下标是current,存放变幻出这些单词的vector下标是pre,那么每一轮要開始更新curr…
这道题是为数不多的感觉在读本科的时候见过的问题. 人工构造的过程是如何呢.兴许遍历最后一个节点一定是整棵树的根节点.从中序遍历中查找到这个元素,就能够把树分为两颗子树,这个元素左側的递归构造左子树,右側的递归构造右子树.元素本身分配空间,作为根节点. 于set和map容器不同的是.vector容器不含find的成员函数.应该用stl的库函数,好在返回的也是迭代器,而vector的迭代器之间是能够做减法的.偏移量非常方便的得到. TreeNode *buildRec(vector<int> &a…
在更新上面一道题的时候我就想,是不是另一道打印路径的,果不其然啊. 这样的题非经常见的,做法也非常easy,我是用一个引用的vector来存,满足条件之后直接压入结果集中,当然也能够用数组之类的,都一样.用引用须要注意的问题就是递归进行到后面的时候会对栈中的上层状态产生影响,当然能够用传值的方法来避免这个问题,可是那样子开销太大了(每次船建和销毁一个类对象,不是明智的选择).那么就是要回退,那什么时候回退,回退多少次呢?我觉得能够这样确定,在一层递归中,压入和弹出要成对出现,在这种方法中压入了几…
这个题比刚才那个更难. 假设没做过上一个,这个简直是无情. 先想一个笨笨的解法,如何确定一个矩形呢?找一个左上角,然后每行的看能延伸到什么位置.注意随着行数的添加,列数是仅仅能变短,不能变长. 想一下也知道这样的方法的复杂度有多高.超时无疑. 假设刚好做了这个求柱形的题目.会不会收到启示呢.将矩阵中的每个1都看做是一个小的正方形.在每一列,连续的1就构成了一个柱体.求一连串这种柱体围成的最大面积就是全部1构成的最大矩形,问题被完美转化. 尽管在我看来.这种转化是非常不easy的,要不是这两个题目…
递归实现当然太简单,也用不着为了ac走这样的捷径吧..非递归实现还挺有意思的. 树的非递归遍历一定要借助栈,相当于把原来编译器做的事情显式的写出来.对于中序遍历,先要訪问最左下的节点,一定是进入循环后,不断的往左下走,走到不能走为止,这时候,能够从栈中弹出訪问的节点,相当于"左根右"过程的"根",然后应该怎么做呢?想一下中序遍历完根节点之后应该干嘛,对,是走到右子树中继续反复这个过程,可是有一点,假设这个节点不包括右子树怎么办?这样的情况下,下一个应该訪问的节点应该…
非常难的问题,数组线性时间. 属于我之前说的解法的借助辅助空间.给定两个柱子,他们之间的面积由什么确定呢?没错,他们之间的距离和他们之间最矮的那个柱子的高度.我们并不知道这个柱子在什么位置,所以仅仅能遍历,这个复杂度就上去了.那有没有一个方法避免找中间小柱子呢?先想什么情况下不用找.除非你知道枚举出两个位置之间的柱子都比方今这个长.所以想到了用一个栈来保存较长的那些柱子编号.须要保证的一件事是栈里面的柱子高度一定是递增的,每次计算面积的时候是从当前位置往前计算的,计算一次弹出一次,每次都使用栈顶…
从左上到右下,仅仅能向右或向下,问一共同拥有多少种走法. 这个问题当然能够用递归和dp来做,递归的问题是非常可能会超时,dp的问题是须要额外空间. 事实上没有其它限制条件的话,这个问题有个非常easy的解法.给定一个格子.如果是m*n的.从左上角走到右下角的总步数是确定了的,(m+n-2)嘛,即在竖直方向一定要走m-1步.在水平方向一定要走n-1步.那有多少种解法就相当于确定什么时候往下走,什么时候往右走,也即相当于从这m+n-2步中.挑选出m-1步有多少种挑法,由于剩下的肯定要往右走嘛.问题实…
好,二叉搜索树粉末登场,有关他的问题有这么几个,给你一个n,如何求全部的n个节点的二叉搜索树个数?能不能把全部的这些二叉搜索树打印出来? 这道题倒不用考虑这么多,直接转即可了,我用的思想是分治,每次找到一半的位置,分离出中间节点,作为新子树的根节点,然后递归构造前半部分和后半部分. class Solution { public: TreeNode *sortedListToBST(ListNode *head) { if(head == NULL) return NULL; int len =…
高速乘方的算法,写了好多变,出了各种错,真是服了我自己了. 思想是每次对n减半,将当前的temp平方.须要注意的是假设当前的n是个奇数,减半之后会丢失掉一次乘积,因此假设当前的n为奇数,应该先在结果里面乘一个temp. 还有,n可能是负数,负数的次方最后要求一次倒数. class Solution { public: double pow(double x, int n) { if(n == 0) return 1; if(n == 1) return x; double res = 1, te…
水题,只是思想还是实用的. 当然能够新建出一个数组.比較着拷贝过去.可是没有必要啊亲.想想为什么用源数组会麻烦,由于确定了前面的数.为了后面的数字不被覆盖,要依次往后移,转念一想,先确定后面的数字.就不用操心会覆盖的问题了.像不像杨辉三角形中仅仅要求O(N)空间时的思想,好多好多样例. class Solution { public: void merge(int A[], int m, int B[], int n) { int i=m-1, j = n-1, k = m+n-1; while…
这道题预计是ac率最高的一道了.你当然能够用层序遍历,我佩服你的耐心和勇气.由于看到别人的三行代码,会不会流眼泪呢.. class Solution { public: int maxDepth(TreeNode *root) { if(root == NULL) return 0; if(!root->left&&!root->right) return 1; return max(maxDepth(root->left), maxDepth(root->righ…
能够用递归简洁的写出,可是会超时. dp嘛.这个问题须要从后往前算,最右下角的小规模是已知的,边界也非常明显,是最后一行和最后一列,行走方向的限制决定了这些位置的走法是唯一的,能够先算出来.然后不断的往前推算. 用distance[i][j]保存从当前位置走到最右下角所需的最短距离,状态转移方程是从distance[i+1][j]和distance[i][j+1]中选一个小的,然后再加上自身的. 代码非常easy理解,这就是dp的魅力.空间上是能够优化的,由于当前状态仅仅与后一行和后一列有关系.…
跟上一题的策略全然一样,这个题是要求保存当前增加的是第几个数,由于矩阵里面存的就是这个东西. 我有尝试想过是不是有一种方法能够直接推算出每一行的数据是哪些.但没过多久就放弃了.这样的方法尽管能够避免在一个二维数组中的随机訪问,可是策略太复杂了,得不偿失. class Solution { public: vector<vector<int> > generateMatrix(int n) { vector<int> tpres(n, 0); vector<vect…
不是非常明确出题人的意图,事实上这道题用java的话简直是太简单了,用split处理一下,得到全部单词的一个数组,然后求最后一个的长度即可了.我个人认为java里最成功的函数就是split了,我做project时差点儿总能用到它,方便强大. c++里面略微复杂一些,只是这也算是最简单的字符串的问题了.函数的接口决定了字符串的长度是未知的,要自己循环找一下,然后从尾向头找不等于空格的字符,找到了就找到了最后一个单词,然后累计直到空格结束. class Solution { public: int…
这道题的难度跟微软的那道面试题相当. 要在集合中插入一段新的集合,相当于求两个集合的并了.对于新增加一段集合的情况,分为以下几种: 1. 增加段跟原来的全然相交,也即他的起点和终点都在被包括在原来的段中了. 这样的情况要合并这之间的段,终于增加段的起点是原来段的起点,终点是原来段的终点. 2. 增加段的起点与原来的相交.终点没有相交.终于增加的段的起点是起点相交的段的起点.终点是增加段的终点. 3. 增加段的终点与原来的相交,起点没有相交.终于增加段的起点是增加段的起点,终点是相交段的终点. 4…
这个题好无趣,竟然输出解的个数.前一个题把全部解都输出出来了.还愁不知道解的个数吗. . 我怀疑这个解的个数是有一个类似通项的东西,就上网查了一下.没有啊亲,最后就把上一题的代码略微改了一下过掉了. class Solution { public: int totalNQueens(int n) { if(n == 0) return 0; int pos[n], res=0, start=0; bool flag, vis[n]; memset(pos, 0, sizeof(pos)); me…