Leetcode:Pow(x, n)

Pow(x, n)

A very easy problem, first I try to use just one loop for n-1, multiply x each time(consider the negative number in different situation ). This solution pass the small data, but fail the large data. Thus, we try to use a smart method, we use binary divide n to get the x^n.We can use recursion to simplify the code.

class Solution

{

private:

double base;

double powIndeed(long long n)

{

if (n==0) return 1;

if (n==1) return base;

double nDivideTwo=powIndeed(n/2);

double nModTwo=powIndeed(n%2);

return (nDivideTwo*nDivideTwo*nModTwo);

}

public:

double pow(double x, int n) {

// Start typing your C/C++ solution below

// DO NOT write int main() function

if (n>=0) base=x;

else base=1/x;

if (n<0) return powIndeed(-(long long)n);

else return powIndeed((long long)n);

}

};

Notice:
There will be -2147483648 in large data test. If you just use -n instead of -(long long)n, it will overflow.(labs in math library has the same result).At first, I got puzzle when the OJ indicated the code has runtime error.(I thought something wrong with the type transformation in my code.Actually, it should be over time limit,because labs(-2147483648) will return -2147483648)

Leetcode:N-Queens I and II

N-QueensI

N-QueensI(2)

The solution to this problem  is backtracking. Notice, we can use an array to represent the trial result(because every row must has and only has one queen.Each cell in the array represent the choice of each row.When we found a solution to putting queens, we can transform the array from one dimension to two dimension(“…..Q…”).) Most important, we could use

(abs(i-putQueenI)==abs(queenStatus[i]-putQueenJ))

to judge if the new putting location is suitable for diagonal(the queens it put before). Here, i means the row it put before,queenStatus[i] means the place it put on in that row. putQueenI and putQueenJ are the new putting location.

/*

一开始写了深度优先和广度优先的版本都不成功(深度的超时,广度的超内存)。发觉自己的算法没有优化,好多地方都耗时间,优化后用一维数组记录就可以了。(一开始用二维数组后面发觉判断只需要一维就可以了)

*/

//维持一个一维数组,而不是二维的,最后需要输入答案的时候才转换成二维的输入

class Solution

{

private:

vector<vector<string> >result;

//转换成二维数组的函数

vector<string> transformToMatrix(vector<int> queenStatus,int n)

{

vector<string> matrix(n,string(n,'.'));

for (int i=0; i<n; i++)

{

matrix[i][queenStatus[i]]='Q';

}

return matrix;

}

//检查是否能在那个位置放置皇后

bool check(vector<int> &queenStatus,int putQueenI,int putQueenJ,int n)

{

for (int i=0; i<putQueenI; i++)

{

if (queenStatus[i]==putQueenJ) return false; //检查纵向

if (abs(i-putQueenI)==abs(queenStatus[i]-putQueenJ)) return false;//检查斜线

}

return true;

}

//回溯使用的函数

void putQueen(int index,vector<int> &queenStatus,int n)

{

if (index>=n)

{

result.push_back(transformToMatrix(queenStatus,n));

return;

}

for (int j=0; j<n; j++)

{

if (check(queenStatus,index,j,n))

{

queenStatus[index]=j;

putQueen(index+1,queenStatus,n);

queenStatus[index]=-1;

}

}

}

public:

vector<vector<string> > solveNQueens(int n) {

// Start typing your C/C++ solution below

// DO NOT write int main() function

result.clear();

vector<int> queenStatus(n,-1);

putQueen(0,queenStatus,n);

return result;

}

};

N-QueensII
Actually, we can use the same solution of N-Queens to solve this problem.Instead of recording all the solution of putting queens, we just add 1 to a counter when we found a solution of putting queens on the chessboard.

class Solution {

private:

int result;

//检查是否能在那个位置放置皇后

bool check(vector<int> &queenStatus,int putQueenI,int putQueenJ,int n)

{

for (int i=0; i<putQueenI; i++)

{

if (queenStatus[i]==putQueenJ) return false; //检查纵向

if (abs(i-putQueenI)==abs(queenStatus[i]-putQueenJ)) return false;//检查斜线

}

return true;

}

//回溯使用的函数

void putQueen(int index,vector<int> &queenStatus,int n)

{

if (index>=n)

{

result++;

return;

}

for (int j=0; j<n; j++)

{

if (check(queenStatus,index,j,n))

{

queenStatus[index]=j;

putQueen(index+1,queenStatus,n);

queenStatus[index]=-1;

}

}

}

public:

int totalNQueens(int n) {

// Start typing your C/C++ solution below

// DO NOT write int main() function

result=0;

vector<int> queenStatus(n,-1);

putQueen(0,queenStatus,n);

return result;

}

};

The performance of this method is very low.(The large data Test)
PerformanceI
Then I find another solution on the Internet which is much more faster. The main idea of the second solution is that we mark down the location which could not put queens on in the next row,which means that when we put the queen on that row, we do not need to check the row before to see if there is a queen can eat this queen. And we can use the bit operation to make it faster.(Obviously, this method can also be use to solve N-Queen problem.But in here, I just gave the source code to solve N-QueensII problem)

class Solution {

private:

long upperlimit;

long sum;

void compute(long row,long ld,long rd)

{

if (row!=upperlimit)

{

long pos=upperlimit & ~(row | ld | rd);

while (pos!=0)

{

long p=pos & -pos;

pos=pos-p;

compute(row + p, (ld + p)<< 1, (rd + p)>> 1);

}

}

else

{

sum++;

}

}

public:

int totalNQueens(int n) {

// Start typing your C/C++ solution below

// DO NOT write int main() function

sum=0;

upperlimit=1;

upperlimit=(upperlimit<<n)-1;

compute(0,0,0);

return sum;

}

};

row is the variant indicate the vertical occupation, ld is the left diagonal occupation, rd is the right diagonal occupation.
upperlimit is indicate the final status, for example 1111 (4*4 matrix, four queens) ,111 (3*3 matrix, 3 queens)
row and ld and rd
row | ld | rd are the occupation in that row.(vertical, left diagonal line and right diagonal line) ~(row | ld | rd) represent the position which can put queens (i.e 10011 means position 1, 4, 5 can put queens).Because the length of type long may be larger than the numbers of rows in the chessboard.(The type long may have more than 10 bits, while the chessboard may be only 5*5)Thus, we need to upperlimit & ~(row | ld | rd) which limit the 1 will only at chessboard’s length position(i.e, the result of ~(row | ld | rd) may be 101111…..0101, if the length of the chessboard is 4, only the last four bits is useful. Thus, we need to do this operation)。
while (pos!=0) if the value of pos is 0, it means no position on that row can the queen be put on.
pos & -pos means get the rightest 1.(-pos equals ~pos+1,you can read the related material about the bit operation)
pos=pos-p means that we put the rightest 1 to 0.(Thus, when in the next loop, the code will find the next rightest 1)
row+p means put the related bit from 0 to 1.
(ld + p)<< 1 left diagonal line must shift 1 for the next row.(Because it is diagonal line, the next one will shift 1,you can draw a matrix, it is easy to figure it out )
(rd + p)>> 1 right diagonal line must shift 1 for the next row(The same reason above.)
if (row!=upperlimit) means that every vertical line has a queen.(Because the variant only consider the vertical conflict(no diagonal),which means that every row has a queen. It means it has found a successful solution.)
The rest part is just backtracking which is the same as the solution to problem before.
Performance:
Performance QueensII
The running time is heavily reduced, which indicates high efficiency of the method.

Leetcode:Sqrt(x)

sqrt(x)

It is a very simple problem. We can use the bisection method to solve it.Here,we should pay attention to the overflow problem of the two numbers’ addition.In the code, calculate the mid point value should use long long type or it will cause a overflow problem.

class Solution {

public:

int sqrt(int x) {

// Start typing your C/C++ solution below

// DO NOT write int main() function

int start=0,end=x;

while (start<=end)

{

long long mid=(start+end)/2;

if (mid*mid==x)

{

return mid;

}

else if (mid*mid<x)

{

start=mid+1;

}

else

{

end=mid-1;

}

}

return (start+end)/2;

}

};

When I search on the internet, I found there is another faster solution which is called “Newton’s method”.

sqrt(x)2

If we use the Newton’s method to solve this problem, we need to construct the function first.

Assume,f(y)=y^2-x (x is the number we need to sqrt),then the problem will transform to find the root of f(y)=0.

f'(y)=2*y (derivation)

Thus,

y(n+1)=y(n)-(y(n)^2-x)/(2*y(n)) (According to the wikipedia)

Then we need to find the termination condition. abs(y(n)^2-x)<=0.1 (When we found the target is close enough, we shut down the iteration)

class Solution {

public:

int sqrt(int x) {

// Start typing your C/C++ solution below

// DO NOT write int main() function

double y=x;

while (abs(y*y-x)>=0.1)

{

y=y-(y*y-x)/(2*y);

}

return floor(y);

}

};

Leetcode:Edit Distance

Edit Distance

At first, I think I can get a very simple solution. However, I found the problem has so many corner case. I could not figure it out. Thus, I found a solution on the Internet.The main idea of the solution is dynamic programming.

For example, we want to transform str1 to str2.(By insert, replace or delete)

sstr1(i) is the substring of str1,sstr1(0)is empty string.0<=i<=str1.size().sstr(str1.size()) is str1 itself.

sstr2(j) is the substring of str2,has the same regulation above.

distance(i,j) means that the steps to transfer substring of str1(0 to i) to substring of str2 (0 to j).

At first,d(0,t),0<=t<=str2.size() is t itself.(Obviously, the number of steps from empty string to substring of str2(0 to t) is t (t insertion))

d(k,0),0<=k<=str1.size() is k itself for the same reason.

When we count distance[i][j], we should consider the two situation.

1. The last char of the substring of str1 is equal to the last char of the substring of str2.

It is simple, just equals to distance[i-1][j-1]. Because  for example, sampleString1C is the string1 now, sampleString2C  is the string2.

because their last char is c, which is equal. Thus, the number of steps transform from sampleString1C to sampleString2C is determined by the number of steps from sampleString1 to sampleString2.

2.The last char of the substring of str1 is not equal to the last char of the substring of str2.

(1)replace

distance[i-1][j-1]+1.

For example, sampleString1C and sampleString2D. If we use replace to transform from sampleString1C to sampleString2D.

distance[i-1][j-1] is the number of steps for sampleString1 to sampleString2. (plus 1 is C to D)

(2)add

distance[i][j-1]+1

For example sampleString1C and sampleString2D.First, sampleString1C transform to sampleString2(distance[i][j-1]), then add D at the rear of the string.

(3)delete

distance[i-1][j]+1

For example sampleString1C use one step to sampleString1 and use distance[i-1][j] to transform to sampleString2D.

From the three,choose the minimum one.

Thus, the minimun distance will be at distance[word1.size()][word2.size()].

class Solution {

public:

int minDistance(string word1, string word2) {

// Start typing your C/C++ solution below

// DO NOT write int main() function

vector<vector<int> > distance(word1.length()+1,vector<int> (word2.length()+1,0));

for (int i=0; i<=word1.length(); i++)

{

distance[i][0]=i;

}

for (int j=0; j<=word2.length(); j++)

{

distance[0][j]=j;

}

for (int i=1; i<=word1.length(); i++)

{

for (int j=1; j<=word2.length(); j++)

{

if (word1[i-1]==word2[j-1])

{

distance[i][j]=distance[i-1][j-1];

}

else

{

int replace=distance[i-1][j-1]+1;

int add=distance[i][j-1]+1;

int del=distance[i-1][j]+1;

distance[i][j]=min(min(replace,add),del);

}

}

}

return distance[word1.length()][word2.length()];

}

};

 

Leetcode:Maximal Rectangle

Maximal Rectangle

This problem can easily transforme to the Leetcode:Largest Rectangle in Histogram.We can search the matrix row by row.We consider the continuous 1 as a histogram. Then the largest rectangle of the continues histogram is the maximal rectangle.

/*

之前这道题用了悬线法来解,做完了直方图那题之后,重新回头看这道题,的确可以转化为直方图的那道题,实际上也是一行一行往下排,悬线就相当于直方图,求最大覆盖的矩阵实际上就是求最大的矩形面积,于是尝试做了一下,这里采用算直方图最大面积的方法没有采用stack,而是采用了直接的剪枝。

*/

//一层一层扫描有可能扫描到了,会出现一段一段的直方图,它们中间是被0的点隔开的,这个intervalInfo就是分成段的起始点和终止点

struct intervalInfo

{

int beginIndex;

int endIndex;

};

&nbsp;

class Solution {

public:

int maximalRectangle(vector<vector<char> > &matrix) {

// Start typing your C/C++ solution below

// DO NOT write int main() function

if (matrix.size()==0) return 0;

//和悬线法一样,用一个数组保存高度

vector<int> Height(matrix[0].size(),0);

queue<intervalInfo> layerInterval;//储存每一个分段到这个队列里面

int maxArea=0;

for (int i=0; i<matrix.size(); i++)

{

int beginIndex=-1,endIndex=-1;

//扫描一层的东西,记录分段,并且改变高度的数组

for (int j=0; j<matrix[0].size(); j++)

{

if (matrix[i][j]=='1')

{

Height[j]++;

if (beginIndex==-1) beginIndex=j;

endIndex=j;//只要遇到1就更新后面的数组

if (j==(matrix[0].size()-1))//有可能还没有遇到0,就已经到当前层的尾部了

{

//这种情况下把这个分段压入队列中

intervalInfo tempInfo;

tempInfo.beginIndex=beginIndex;

tempInfo.endIndex=endIndex;

layerInterval.push(tempInfo);

}

}

else

{

if (beginIndex!=-1)

{//遇到0,就检查之前是不是还有段没有压入队列

intervalInfo tempInfo;

tempInfo.beginIndex=beginIndex;

tempInfo.endIndex=endIndex;

layerInterval.push(tempInfo);

}

beginIndex=-1;

endIndex=-1;

Height[j]=0;

}

}

//对于队列里面每一个段进行直方图的处理

while (layerInterval.size()!=0)

{

int nowBegin=layerInterval.front().beginIndex;

int nowEnd=layerInterval.front().endIndex;

layerInterval.pop();

int increaseStart=nowBegin;//就是标定单调递增高度序列的起始点,这里的具体算法需要看直方图的那个程序

while (increaseStart<=nowEnd)

{

int increaseEnd=nowEnd;

for (int k=increaseStart+1; k<=nowEnd; k++)

{

if (Height[k]<Height[k-1])

{

increaseEnd=k-1;

break;

}

}

int minHeight=INT_MAX;

for (int k=increaseEnd; k>=nowBegin; k--)

{

minHeight=min(minHeight,Height[k]);

maxArea=max(maxArea,minHeight*(increaseEnd-k+1));

}

increaseStart=increaseEnd+1;

}

}

}

return maxArea;

}

};

Another solution is what we called “Vertical lines”.One side of the vertical lines may be the boundary of the matrix or a 0. Here, we uses three array to complete this. One array is the height of the each lines above the given row.One array is used to determine the left expand of each line.One array is used to determine the right expand of each line.Here,”expand” means that the line can move left or right.(For example, if the line can expand to the left for one, which means that the length of the left vertical line must be larger than the given one or equal to the given one.) In the code, we use to array to store the left most index of the expand rectangle of a vertical line.Another array to store the right most index of the expand rectangle.(The right most index minus the left most index plus one is the length of the rectangle, multiplied by the height of the vertical line is the area of the rectangle expand by a vertical line.) The largest rectangle among all the expand rectangle is the maximal rectangle of the matrix.
Here,we use recurrence to simplify the implement.Obviously, the height of the vertical line(histogram in the last solution) is influent by the height of last row. The left most index should be larger one of last row and this left most index of this row.(The expand distance is determined by the largest expand distance of the same vertical line above last row and the distance of this row.) For the same reason, right most index is the min value of last row’s and this row.After we scan all the cell of the matrix, we found all the vertical lines and their expand rectangle, then we get the maximal rectangle.

/*

想象成许多悬线,每一条悬线都可以扫出一个矩形,最大值矩形(就是题目要求的)必然在里面......

悬线的意思是指上面的当前点到垂直上方的一个0点或者边界的线段。悬线扫描的矩形是指左右能够到达的最大矩形,不过这个矩形连极大矩形都不算,因为下方情况未知(从上往下一层一层做),不过这些矩形中必然包含最大矩形,因为每一个点都要扫一次。

&nbsp;

*/

class Solution {

public:

int maximalRectangle(vector<vector<char> > &matrix) {

// Start typing your C/C++ solution below

// DO NOT write int main() function

//矩阵里面没有数,必然为0

if (matrix.size()==0) return 0;

vector<int> Height(matrix[0].size(),0);//掌管上一层的悬线高度,一开始肯定设置为0

vector<int> Left(matrix[0].size(),0);//掌管上一层的左边界,一开始肯定设置为0

vector<int> Right(matrix[0].size(),matrix[0].size()-1);//掌管上一层的右边界,一开始设置为matrix[0].size()-1,因为设置右边界一开始肯定是矩阵的最右端

int maxResult=0;

for (int i=0; i<matrix.size(); i++)

{

//一层一层扫描

int left=0,right=matrix[0].size()-1;//当前有可能满足点为1条件的坐标,当然初始化有可能的点为坐标0,右边有可能的点为坐标matrix[0].size()-1

//scan from left to right to fill the height value and the left value

for (int j=0; j<matrix[0].size(); j++)

{

if (matrix[i][j]=='1')

{

Height[j]++;//如果为1,当前的悬线可以加1

Left[j]=max(Left[j],left);//当前层的左边的当然是上一层的值和当前层的左值比较,取大的,因为当前层有可能出现的障碍点更加靠近当前悬线

}

else

{

left=j+1;//有可能出现符合条件的等于当前0点的坐标加1

Height[j]=0;//悬线的长度归0

Left[j]=0;//当前层有可能出现的左边界为0

Right[j]=matrix[0].size()-1;//当前层有可能出现的右边界为matrix[0].size()

}

}

//scan from right to left to fill the right value

for (int j=matrix[0].size()-1; j>=0; j--)

{

if (matrix[i][j]=='1')

{

Right[j]=min(Right[j],right);//同理求右边界

maxResult=max(maxResult,Height[j]*(Right[j]-Left[j]+1));

}

else

{

right=j-1;

}

}

}

return maxResult;

}

};

Leetcode:Largest Rectangle in Histogram

F0E8F3CB-1D90-479F-BBD1-5578E8C3A5D6

The simple solution is easy to figure out, just brute-force all the possibility.

class Solution {

public:

int largestRectangleArea(vector<int> &height) {

// Start typing your C/C++ solution below

// DO NOT write int main() function

int maxArea=0;

for (int i=0; i<height.size(); i++)

{

int minHeight=INT_MAX;

for (int j=i; j>=0; j--)

{

minHeight=min(minHeight,height[j]);

maxArea=max(maxArea,minHeight*(i-j+1));

}

}

return maxArea;

}

};

But this will only pass the small data test.It will fail the large data test.

We need to prune some possibility. For example, if m to n is increasing heights, we should only consider the last one as the last part of the maximal rectangle.It means that we should calculate the minHeight from k to n *(the index of n- the index of k) and renew the value of maximal area.The reason why we only consider the last one of the increasing heights  is that the maximal rectangle formed by the  previous one of the increasing height will always be replaced by the latter one. (The maximal area formed before will stretch because of the larger height.)

class Solution {

public:

int largestRectangleArea(vector<int> &height) {

// Start typing your C/C++ solution below

// DO NOT write int main() function

int increaseBegin=0;//标记单调递增的段的起始点

int maxArea=0;

while (increaseBegin<height.size())

{

int increaseEnd=height.size()-1;//默认单调递增的结束点为整体队列的尾部

for (int j=increaseBegin+1; j<height.size(); j++)

{

if (height[j]<height[j-1])

{

increaseEnd=j-1;//找到不满足单调递增的序列的,就记录并break

break;

}

}

int minHeight=INT_MAX;

for (int j=increaseEnd; j>=0; j--)

{

minHeight=min(minHeight,height[j]);//和之前的解法一样扫描找最小的

maxArea=max(maxArea,minHeight*(increaseEnd-j+1));

}

increaseBegin=increaseEnd+1;

}

return maxArea;

}

};

Another solution is to use a stack to contain the increasing height and its left width. which means that the height may contains a few original rectangles instead of just one. When we deal with a rectangle whose height is larger than the top of the stack, then we put it into the stack. If the height we deal with is smaller than the top of stack, we pop out all the rectangle in the stacks whose height is larger than the one we deal with now.When we pop out, we need to consider the area formed by the popped out rectangle.(Will the rectangle formed by the popped one can be the maximal rectangle).The reason why we can do these is the same as the solution above.Because the lager height in stack could not make any contribution to forming a maximal rectangle of the latter one.(Because the rectangle with smaller height is in the middle.)

struct HeightInfo

{

int height;

int leftWidth;

};

class Solution {

public:

int largestRectangleArea(vector<int> &height) {

// Start typing your C/C++ solution below

// DO NOT write int main() function

stack<HeightInfo> increase;//保存上升高度的栈

//预先压入一个不可能被弹出的方便程序的书写

HeightInfo tempInfo;

tempInfo.height=-1;

tempInfo.leftWidth=0;

increase.push(tempInfo);

int maxArea=0;

for (int i=0; i<=height.size(); i++)

{

//必须要考虑最后所有在栈里面高度的情况,把所有的栈里面的heightInfo都弹出并且进行相应的处理了,所以最后我们需要多一步,处理一个所有的元素都会比它大的,这样就会把所有的元素都弹出来,并且处理了他们的最大面积了

int dealHeigth;

if (i==height.size()) dealHeigth=0;

else dealHeigth=height[i];

int minHeight=INT_MAX;

int nowWidth=0;

//记录新压入的高度能够向左的扩展的长度

while (increase.top().height>=dealHeigth)

{

nowWidth=nowWidth+increase.top().leftWidth;//统计被弹出的HeightInfo的左扩展信息

//考虑被弹出的栈高度信息,有可能是以它为开头,栈顶的那个直方图为结尾组成的面积,这里要进行考虑

maxArea=max(maxArea,increase.top().height*nowWidth);

increase.pop();

}

HeightInfo tempInfo;

tempInfo.height=dealHeigth;

tempInfo.leftWidth=nowWidth+1;

increase.push(tempInfo);

}

return maxArea;

}

};

LeetCode: Reverse Linked List II

// pseudo code
// ReverseBetween()
// add an empty node H whose next points to head of the list, such that H.next would always be the head of the list.
// locate the m-1th and mth nodes, marked as p1 and p2 respectively. If m = 1, then p1 = H
// repeatedly reverse p2 and p2->next until p2->next reach to n+1th element.

class Solution {
public:
 ListNode *reverseBetween(ListNode *head, int m, int n) {
 ListNode tmp(0);
 ListNode *p1,*p2;
 tmp.next = head;
 head = p1 = &tmp;

// locate m-1th and mth
 for (int i = 0; i < m-1; ++i)
 {
 p1 = p1->next;
 }
 p2 = p1->next;

// reverse p2 and p2->next until p2->next reach n+1th
 for (int i = m; i < n; ++i)
 {
 ListNode *p3 = p2->next;
 p2->next = p3->next;
 p3->next = p1->next;
 p1->next = p3;
 }
 return head->next;
 }
};