Categories
不学无术

LeetCode 335. Self Crossing

题目:

You are given an array x of n positive numbers. You start at point (0,0) and moves x[0] metres to the north, then x[1] metres to the west, x[2] metres to the south,x[3] metres to the east and so on. In other words, after each move your direction changes counter-clockwise.
Write a one-pass algorithm with O(1) extra space to determine, if your path crosses itself, or not.
Example 1:

Given x = [2, 1, 1, 2],
┌───┐
│   │
└───┼──>
    │
Return true (self crossing)

Example 2:

Given x = [1, 2, 3, 4],
┌──────┐
│      │
│
│
└────────────>
Return false (not self crossing)

Example 3:

Given x = [1, 1, 1, 1],
┌───┐
│   │
└───┼>
Return true (self crossing)

思路:

https://leetcode.com/discuss/88054/java-oms-with-explanation
本人愚钝,想不到O(1)空间复杂度的方法,只能看Discussion啦,看完以后发现,遇到问题能够分析出各种情况真是不容易。
把大神的代码总结一下,可以变成下面这张图,图中给出了可能发生self-crossing的所有情况(其他情况都是这些情况的”旋转”版本):
LeetCode_Self_Crossing
所以就是遍历所有移动步x[i],判断之前的情况是否在这三种情况之内,如果有的话,那肯定就有crossing了。其中情况2的意思是,当前的步进x[i]覆盖到了x[i-4]了,其他情况看图应该都好理解的。

代码:

class Solution {
public:
    bool isSelfCrossing(vector<int>& x) {
        int numSz = x.size();
        if(numSz <= 3)
            return false;
        for(int i=3; i<numSz; i++){
            if(x[i]>=x[i-2] && x[i-1]<=x[i-3]) //Cond 1
                return true;
            else if(i>=4 && x[i-1]==x[i-3] && x[i]+x[i-4]>=x[i-2])//Cond 2
                return true;
            else if(i>=5 && x[i-1]<=x[i-3] && x[i-4]<=x[i-2] && x[i]+x[i-4]>=x[i-2] && x[i-1]+x[i-5]>=x[i-3]) //Cond 3
                return true;
        }
        return false;
    }
};

 

Categories
不学无术 木有技术

百度前端技术学院 任务四:定位和居中问题

任务:

http://ife.baidu.com/task/detail?taskId=4

效果图:

屏幕快照 2016-04-03 下午5.54.13

有用的参考资料:

思路:

灰色矩形使用relative定位,然后设定left与top为50%,由于已经知道框的大小,用margin把长款的一半距离补回来就行了。
两个扇形在矩形的div内部,使用绝对定位,用border-radius做圆角,clip:rect剪切。

代码:

CodePen: http://codepen.io/idailylife/full/QNqJXe/

<div class="rectangle">
  <div id="left_top" class="qcircle">
  </div>
  <div id="right_bottom" class="qcircle">
  </div>
</div>

 

.rectangle{
  position: absolute;
  width: 400px;
  height: 200px;
  top: 50%;
  left: 50%;
  margin-left: -200px;
  margin-top:-100px;
  background-color: #ccc;
}
.qcircle{
  position:absolute;
  width:100px;
  height:100px;
  border-radius:50px;
  background-color:#fc0;
}
#left_top{
  top: -50px;
  left: -50px;
  clip:rect(50px, 100px, 100px, 50px);
}
#right_bottom{
  right: -50px;
  bottom: -50px;
  clip:rect(0, 50px, 50px, 0);
}

 

Categories
不学无术 木有技术

百度前端技术学院 任务三 HTML、CSS布局入门,三栏式布局的实践

恩,很遗憾没有赶上报名,因为是事后好几天才知道的。好在他们公开了练习题已经微信通知,所以还是可以跟着练一练哒!就是得不到别人的评论了,很忧伤,但是可以看每一队提交的作业,挺好。
给出我自己的实现吧,作为“对于有过页面实践,但没做过太复杂页面的同学”,我先选了第三题
效果图:
屏幕快照 2016-04-02 下午6.42.20
实现:
三栏布局使用的是float,没有用到相对定位。文字在框里的垂直居中,找到的是这里的方法。
前端团队提供的有关清除浮动的信息很给力:http://zh.learnlayout.com/clearfix.html,里面还有些很实用的技巧。
目前的缺陷是,强制设置了min-width,移动界面不适配,我还要慢慢学习啊!
代码:
CodePen: https://codepen.io/idailylife/pen/pyWLvq
HTML

<div class="container">
  <div id="group" class="nav sub container">
    <div id="group_logo" class="smallbox container">
      团队LOGO</br>80x80
    </div>
    <div id="group_name">
      团队名称
    </div>
  </div>
  <div id="right" class="right sub container">
    <div class="plogo smallbox container withvmargin">
      <p>个人LOGO</p>
    </div>
    <div class="plogo smallbox container withvmargin">
      <p>个人LOGO</p>
    </div>
    <div class="plogo smallbox container withvmargin">
      <p>个人LOGO</p>
    </div>
    <div class="plogo smallbox container">
      <p>个人LOGO</p>
    </div>
  </div>
  <div id="middle" class="sub container">
    <p>团队介绍</p>
    <p>《金刚般若波罗蜜经》来自印度的初期大乘佛教。因其包含根本般若的重要思想,在般若系大乘经中被视为一个略本;本经说“无相”而不说“空”,保持了原始般若的古风。本经六种译本中,通常流通的是鸠摩罗什的初译。如印顺法师所说,此后的五译是同一唯识系的诵本,比如菩提流支、达摩笈多等,都是依无著、世亲的释本译出;只有罗什所译为中观家(般若系)的诵本。又如吕澂说,罗什传龙树的般若学,所以能“心知其意”;到玄奘新译般若经,《金刚经》其实已“面目全非”了。
《金刚经》在印度有唯识家(无著、世亲)的论释。传入中国,三论、天台、贤首、唯识各宗都有注疏;然而中国佛教深受真常系大乘的影响,各宗表面上阐扬《金刚经》,实际上阐扬常住佛性和如来藏。又在三教合流环境下,明清以来,三教九流都来注解《金刚经》,杂合浓厚的真常理论和儒道信仰。又受到密教影响,《金刚经》被附上密咒形成读诵仪轨。此外,民间还出现各种离奇的灵验记和感应录。般若经典《金刚经》被真常化、儒道化、迷信化之中,在中国特别的盛行起来。
本经文义次第的艰深为古印度学者所公认,如无著说:“金刚难坏句义聚,一切圣人不能入”。依龙树所示《般若经》的“两番嘱累”,《金刚经》的“初问初答”即宣说“般若道”,“再问再答”宣说“方便道”。本经侧重广观万法(《心经》则侧重观身心五蕴),阐扬发菩提心,行无我的大乘菩萨道;彻始彻终归宗於般若无住的离相法门,以此明示阿耨多罗三藐三菩提。</p>
  </div>
</div>

CSS

body{
  min-width:540px;
}
.container{
    padding: 20px;
    background-color: #eee;
    border: 1px solid #999;
    overflow: auto;
    zoom: 1;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
}
.sub{
  background-color: #fff;
}
.nav{
  float:left;
  width:200px;
}
.right{
  width:120px;
  float:right;
}
.smallbox{
  width:80px;
  height:80px;
  float:left;
  overflow:hidden;
}
.withvmargin{
  margin-bottom:20px;
}
.plogo{
  padding:20px 0;
  font-size: 12px;
  text-align:center;
}
#group_name{
  margin: 0px auto;
  width: 78px;
  font-size: 16px;
  float: left;
  text-align:right;
}
#group_logo{
  font-size: 12px;
  padding: 0 auto;
}
#middle{
  margin-left: 220px;
  margin-right: 140px;
}

 

Categories
不学无术

LeetCode 142. Linked List Cycle II

Given a linked list, return the node where the cycle begins. If there is no cycle, return null.
Note: Do not modify the linked list.
Follow up:
Can you solve it without using extra space?

思路

其实还有更简单的方法,在《Cracking the Coding Interview》上有提到。通过数学计算可以推导出来,用快行指针的方法判断出环后,可以不用计算环大小,把快指针变慢然后放到链头上,两个指针继续走到相碰就剩入口了。
分为三步:判断环,计算环的大小,找到入口
判断环就是老一套,用2倍速指针就行,这个之前的题目里头有;
计算环的大小k,环的大小么,刚才相碰的地方找个指针绕圈圈走。记个数,再碰到相遇地点就是环大小了;
找到入口后,我们有两个普通速度的指针pA,pB,让其中一个pA先往前走k步,然后两个一起开始挪动,可以知道,如果pA与pB又相遇了,那相遇点就是环的入口了。此时pA比pB刚好多走了一整圈。

代码

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
    ListNode* meetingNode(ListNode* head){
        //Find the meeting node
        if(head == NULL)
            return NULL;
        ListNode* slow = head->next;
        if(slow == NULL)
            return NULL;
        ListNode* fast = slow->next;
        while(fast != NULL && slow != NULL){
            if (slow == fast)
                return slow;
            slow = slow->next;
            fast = fast->next;
            if(fast != NULL)
                fast = fast->next;
        }
        return NULL;
    }
    ListNode *detectCycle(ListNode *head) {
        ListNode* meet = meetingNode(head);
        if(meet == NULL)
            return NULL;
        //Get loop size
        ListNode* temp = meet->next;
        int count = 1;
        while(temp != meet){
            count++;
            temp = temp->next;
        }
        //Pick one pointer at start, move `count` steps forward
        temp = head;
        meet = head;
        while(count > 0){
            count--;
            meet = meet->next;
        }
        //Find the cycle start
        while(temp != meet){
            temp = temp->next;
            meet = meet->next;
        }
        return meet;
    }
};

 

Categories
不学无术

LeetCode 287. Find the Duplicate Number | 智商被碾压!

看了LeetCode上牛人的解答,感觉我的智商被碾压了~

原题

Given an array nums containing n + 1 integers where each integer is between 1 and n (inclusive), prove that at least one duplicate number must exist. Assume that there is only one duplicate number, find the duplicate one.
给定一个包含n+1个整数的数组nums,该数组中的每个整数都在[1,n]的范围内,假设数组中只有一个数是重复的,找到那个重复的数。
Note|提示:

  1. You must not modify the array (assume the array is read only).|    不能改动数组内容
  2. You must use only constant, O(1) extra space.|    在O(1)的空间复杂度内完成
  3. Your runtime complexity should be less than O(n2).|    时间复杂度不超过O(n^2)
  4. There is only one duplicate number in the array, but it could be repeated more than once.|    只有一个重复数字,但是可能重复超过一次

思路1:O(nlogn)时间复杂度

英文版解释:https://leetcode.com/discuss/60830/solutions-explanation-space-without-changing-input-array
这个解法涉及到鸽巢原理。
假设有n=10的一个数组(大小是n+1),那我目前的搜索范围是[1,10],先找中间的数mid=5.现在我们遍历数组的所有元素并统计<=5的元素个数,记作n_lteq5好了,那么有:

  • 如果n_lteq5>5,那就有6个数字占了本来只有5个的坑位,那目标数字肯定是在[1,5]的范围内了;
  • 如果n_lteq5<=5,那前面的元素都挺守规矩的,得看看[6,10]里头哪个数字在作怪;

这样每一次判断,问题的规模都会缩小一半,一共n+1个数字,时间复杂度是O(nlogn)
感觉碰到了很多二分思想的题目啊,关键点就是要找到一个什么划分方式把问题的规模缩小掉,而在这道题里头用到的就是鸽巢原理。

思路1代码

class Solution {
public:
    int countLtEq(const vector<int>& nums, int n){
        int count = 0;
        for(int i=0; i<nums.size(); i++){
            if(nums[i] <= n)
                count ++;
        }
        return count;
    }
    int findDuplicate(vector<int>& nums) {
        int n = nums.size() - 1;
        int min = 1, max = n;
        int mid;
        int ltEqCnt;
        while(min < max){
            mid = (min + max)/2;
            ltEqCnt = countLtEq(nums, mid);
            if(ltEqCnt <= mid){
                //[min, mid]是正常的,找另一边
                min = mid+1;
            } else {
                max = mid;
            }
        }
        return min; // min == max
    }
};

 

插曲:如果可以改变数组元素呢?

感觉在剑指Offer上遇到过类似的题目。如果可以改变数组元素的话,可以按照下面的思路进行,时间复杂度是O(n)。基本思想是,一个萝卜一个坑,把搜索到的数放到自己应该在的位置上,比如1应该放在第一个位置上,如果后面再找到一个1,我们就会发现1这个位置的坑被前一个1占了,那就冲突了。
方便起见,数组的位置按1,2,3,…描述(而非0,1,2…)。假设有数组[5,4,2,3,1,5,6] ,当前工作的位置pos=1

  • 先看第pos=1个数字5,在设想的排好序的序列里,5应该就在第5个位置上,因此我们把5和第5个位置上现有的数字1进行调换,结果就变成了[1,4,2,3,5,5,6] ;
  • 看换回来的数字1,由于已经在1号位上,这次处理就结束了,往前挪一下,pos=2,看下一个数字;
  • pos=2的数字是4,本来应该在4号位上,因此把4和4号位上的 3调换,数组变成[1,3,2,4,5,5,6] ;
  • 这时候事情没完,因为换回来的3不在应该有的3号位上,因此把3和3号位上占着的2调换,数组变成[1,2,3,4,5,5,6] ;
  • 换回的数字2是正确的位置,因此pos++,变成pos=3,类似地检查pos=4, 5发现都符合要求;
  • pos=6时,此时位置上的元素是5,于是我们想把这个5归为到5号位,但是检查5号位的时候我们发现,上面已经有一个5了,这就说明5是重复数值了,搞定

可能有问,那如果原来的数组是[5,4,2,3,1,6,5] 呢?很显然,如果前面找到pos=6的时候都没发生冲突,那罪魁祸首肯定在最后个元素上面了。
这种方法只要遍历一次数组并做相应替换就行,除了会改变数组内容外,其他条件都满足,可惜啊。

思路2:O(n)时间复杂度

大神,大家快去膜拜:http://keithschwarz.com/interesting/code/?dir=find-duplicate
据说越是经典的代码行数越是写的简单,然而你并不能看懂…
似乎是把数组中的值看做单链表的next指针的值的,还在理解中~这个算法理论上是正确的。
 

Categories
不学无术

LeetCode 330. Patching Array

题目

Given a sorted positive integer array nums and an integer n, add/patch elements to the array such that any number in range [1, n] inclusive can be formed by the sum of some elements in the array. Return the minimum number of patches required.
Example 1:
nums = [1, 3], n = 6
Return 1.
Combinations of nums are [1], [3], [1,3], which form possible sums of: 1, 3, 4.
Now if we add/patch 2 to nums, the combinations are: [1], [2], [3], [1,3], [2,3], [1,2,3].
Possible sums are 1, 2, 3, 4, 5, 6, which now covers the range [1, 6].
So we only need 1 patch.
Example 2:
nums = [1, 5, 10], n = 20
Return 2.
The two patches can be [2, 4].
Example 3:
nums = [1, 2, 2], n = 5
Return 0.

思路

说实话这道题没有想出来,还以为是个排列组合的问题,后来看了解释才恍然大悟。网上版本有很多种,我看的官网discussion里头的(这里)。
思路就是贪心法,假设目标是覆盖[0,n],当前我们的组合能够覆盖[0,miss)的数字(注意这里的miss是目前无法到达的目标,我们得用贪心的思想让这个目标可达),并且目前正在处理有序数组中num[i]的数,那么有两种情况需要考虑:

  • 如果num[i]比miss来的小,说明总有一个之前有的数,加上了num[i]以后能够到达miss完成任务。因为我们比较贪心,想让可覆盖的数越多越好,所以把num[i]带上,得到最大可以覆盖的范围[0,miss+num[i]);
  • 如果num[i]比miss来的大,那么显然把num[i]加进去是无法得到miss的。比如:目前有0,1,2,…,9可以覆盖(即miss=10),来了个num[i]=12的,显然加入12并不能解决覆盖10的问题(试想一下0+12都比10来的大)。所以最经济实惠的办法就是把miss自己加进去,这样还能把覆盖范围拓展到[0,miss*2);

代码

class Solution {
public:
    int minPatches(vector<int>& nums, int n) {
        long known_sum = 1, count = 0, i = 0;
        while(known_sum <= n){
            if(i < nums.size() && nums[i]<=known_sum){
                //If we have a choice to expand the range
                known_sum += nums[i++]; //The best choice is to add nums[i] in, which can reach up to (known+nums[i])
            } else {
                //Or we have to add in one item to make the best range, which means to double the range to 2*known_sum
                known_sum += known_sum;
                count++;
            }
        }
        return count;
    }
};

 

Categories
不学无术

LeetCode 36. Valid Sudoku

Determine if a Sudoku is valid, according to: Sudoku Puzzles – The Rules.
The Sudoku board could be partially filled, where empty cells are filled with the character '.'.

A partially filled sudoku which is valid.
Note:
A valid Sudoku board (partially filled) is not necessarily solvable. Only the filled cells need to be validated.

思路

行搜索、列搜索、sub-box搜索,根据规则来就行了

代码

class Solution {
public:
    bool isValidSudoku(vector<vector<char>>& board) {
        set<char> workingSet;
        // Row
        char c;
        for(int row = 0; row<9; row++){
            workingSet.clear();
            for(int col=0; col<9; col++){
                c = board[row][col];
                if(c == '.')
                    continue;
                if(workingSet.count(c) > 0)
                    return false;
                workingSet.insert(c);
            }
        }
        // Col
        for(int col = 0; col<9; col++){
            workingSet.clear();
            for(int row=0; row<9; row++){
                c = board[row][col];
                if(c == '.')
                    continue;
                if(workingSet.count(c) > 0)
                    return false;
                workingSet.insert(c);
            }
        }
        // Sub-box
        for(int lPos=0; lPos < 9; lPos+=3){
            for(int tPos=0; tPos<9; tPos+=3){
                workingSet.clear();
                for(int i=0; i<3; i++){
                    for(int j=0; j<3; j++){
                        c = board[lPos+i][tPos+j];
                        if(c == '.')
                            continue;
                        if(workingSet.count(c) > 0)
                            return false;
                        workingSet.insert(c);
                    }
                }
            }
        }
        return true;
    }
};

 

Categories
不学无术

LeetCode 264. Ugly Number II

Write a program to find the n-th ugly number.
Ugly numbers are positive numbers whose prime factors only include 2, 3, 5. For example, 1, 2, 3, 4, 5, 6, 8, 9, 10, 12 is the sequence of the first 10 ugly numbers.
Note that 1 is typically treated as an ugly number.

思路

《剑指Offer》上的原题34,所以就说个大概吧。
下一个丑数是之前的丑数(最初是1)乘以2、3或者5得到的,所以下一个丑数就是之前的某个数乘出来的。这样的找法比从1到n一个个判断是不是丑数高效很多,不然每个数都要去除个2、3、5判断一下。
由于要管次序问题,所以安排三个指针,分别记录乘以2、3、5后不超过当前最大丑数的位置,假设是p2, p3, p5,下一次找下个丑数的时候,从(p2)2、(p3)3、(p5)5里头找到个最小的,加在数组最后面,然后更新三个指针的值,如此往复……

代码

class Solution {
public:
    int nthUglyNumber(int n) {
        if(n <= 0)
            return 0;
        int* uglyAry = new int[n];
        uglyAry[0] = 1;
        int nextPos = 1;
        int *pNextUgly2 = uglyAry;
        int *pNextUgly3 = uglyAry;
        int *pNextUgly5 = uglyAry;
        while(nextPos < n){
            int nextUgly = min3(*pNextUgly2 * 2, *pNextUgly3 * 3, *pNextUgly5 * 5);
            uglyAry[nextPos] = nextUgly;
            //Move forward to find next possible candidates
            while(*pNextUgly2 * 2 <= nextUgly)
                pNextUgly2++;
            while(*pNextUgly3 * 3 <= nextUgly)
                pNextUgly3++;
            while(*pNextUgly5 * 5 <= nextUgly)
                pNextUgly5++;
            nextPos++;
        }
        int ugly = uglyAry[n-1];
        delete []uglyAry;
        return ugly;
    }
    int min3(int n1, int n2, int n3){
        int min = n1<n2?n1:n2;
        min = min<n3?min:n3;
        return min;
    }
};

 
 

Categories
不学无术

LeetCode 257. Binary Tree Paths

Given a binary tree, return all root-to-leaf paths.
For example, given the following binary tree:

   1
 /   \
2     3
 \
  5

All root-to-leaf paths are:

["1->2->5", "1->3"]

代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    vector<string> binaryTreePaths(TreeNode* root) {
        vector<string> results;
        vector<int> path;
        binaryTreePaths(root, path, results);
        return results;
    }
    void binaryTreePaths(TreeNode* root, vector<int> path, vector<string>& results){
        if(root == NULL){
            //Error
            return;
        }
        path.push_back(root->val);
        if(root->left == NULL && root->right == NULL) {
            //Leaf
            string result;
            int pSize = path.size();
            for(int i=0; i<pSize; i++){
                result += to_string(path[i]);
                if(i != pSize - 1)
                    result += "->";
            }
            results.push_back(result);
        } else {
            if(root->left != NULL)
                binaryTreePaths(root->left, path, results);
            if(root->right != NULL)
                binaryTreePaths(root->right, path, results);
        }
    }
};

 
 

Categories
不学无术

LeetCode 169. Majority Element My Submissions Question

Given an array of size n, find the majority element. The majority element is the element that appears more than ⌊ n/2 ⌋ times.
You may assume that the array is non-empty and the majority element always exist in the array.

思路

多数投票嘛,这个题目当年NB哄哄的数据库老师在课堂上提到过,至今印象深刻,跟我们说选班长的时候画正字就是在浪费空间(当然要保证半数通过的前提)。
假设当前候选人A唱了三票,那么小黑板上A的“正”字记了三笔;这时候有了B的一票,由于我们只要统计排名第一的人,此时可以把A的正字划去一票,而不是重新记一个“B,一票”。因为照这样计算,如果B再唱了两票,那两个人的票刚好抵消,小黑板被擦干净,这时候不管是谁得了一票就写在小黑板上重新计数啦

思路2

设想一下排序后的数列,如果有个元素占了超过半数的位置,那么它肯定也是这个数列的中位数。参考快速排序的思想,可以在O(n)的复杂度找到这个中位数,它也就是要得到的结果。(参考数组第k大数的那个递归方法

代码(思路1)

class Solution {
public:
    int majorityElement(vector<int>& nums) {
        int majNum = -1;
        int majCount = 0;
        int numSz = nums.size();
        for(int i=0; i<numSz; i++){
            if(majNum != nums[i]){
                if(majCount == 0){
                    majNum = nums[i];
                    majCount = 1;
                } else {
                    majCount--;
                }
            } else {
                majCount++;
            }
        }
        return majNum;
    }
};