您的位置:首页 > 其它

leetCode解题报告5道题(九)

2014-05-31 13:29 513 查看

题目一:Combinations

Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.

For example,

If n = 4 and k = 2, a solution is:

[
[2,4],
[3,4],
[2,3],
[1,2],
[1,3],
[1,4],
]


分析:

题意给我们一个数字n, 和一个数字k,让我们求出从 1~~n中取出k个数所能得到的组合数

所以这个题目给我们的第一感觉就是用递归是最方便的了,咱试试递归的方法哈。假设读者对递归方法有疑问,能够看看我之前总结的一个递归算法的集合。

本文专注于<递归算法和分治思想>

AC代码:

public class Solution {
//终于结果
private ArrayList<ArrayList<Integer>> arrays = new ArrayList<ArrayList<Integer>>();

public ArrayList<ArrayList<Integer>> combine(int n, int k) {
//把组合设想成仅仅能升序的话,能做开头的数字仅仅有 1 ~ n-k+1
for (int i=1; i<=n-k+1; ++i){
ArrayList<Integer> list = new ArrayList<Integer>();
list.add(i);
cal(list, i+1, n, k-1); //递归
}
return arrays;
}
public void cal(ArrayList<Integer> list, int start, int end, int k){
//k==0表示这次list组合满足条件了
if (k == 0){
//copy
ArrayList<Integer> result = new ArrayList<Integer>(list);
arrays.add(result);
}
//循环递归调用
for (int i=start; i<=end; ++i){
list.add(i);
cal(list, i+1, end, k-1);
list.remove(list.size()-1);
}
}
}


题目二:Search a 2D Matrix

Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

Integers in each row are sorted from left to right.
The first integer of each row is greater than the last integer of the previous row.

For example,

Consider the following matrix:

[
[1,   3,  5,  7],
[10, 11, 16, 20],
[23, 30, 34, 50]
]


Given target =
3
, return
true
.

分析:这道题目是剑指Offer上的老题目咯,可是解题的思路挺巧妙。本来不想把这题写在博文里的,后来想想或许有些同学没看过剑指Offer, 后续由于这题而去看下这本挺不错的书哈,于是把这题写在博文里了。并附上剑指offer的下载地址(http://download.csdn.net/detail/u011133213/7268315),这题便不做具体介绍。

AC代码:(复杂度O(m+n))

public class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length;
int n = matrix[0].length;
int row = 0;
int col = n - 1;
while (m > row && col >= 0){
if (target == matrix[row][col]){
return true;
}
if (target > matrix[row][col]){
row++;//往下一行搜索
}else if (target < matrix[row][col]){
col--;//往左一列搜索
}
}
return false;
}
}


题目三:Scramble String

Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.

Below is one possible representation of s1 =
"great"
:

great
/    \
gr    eat
/ \    /  \
g   r  e   at
/ \
a   t


To scramble the string, we may choose any non-leaf node and swap its two children.

For example, if we choose the node
"gr"
and swap its two children, it
produces a scrambled string
"rgeat"
.

rgeat
/    \
rg    eat
/ \    /  \
r   g  e   at
/ \
a   t


We say that
"rgeat"
is a scrambled string of
"great"
.

Similarly, if we continue to swap the children of nodes
"eat"
and
"at"
,
it produces a scrambled string
"rgtae"
.

rgtae
/    \
rg    tae
/ \    /  \
r   g  ta  e
/ \
t   a


We say that
"rgtae"
is a scrambled string of
"great"
.

Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1.

分析:

这道题目的题意相信大家应该都看得懂,仅仅是做起来的话有些蛋疼.

我一開始用暴力法TLE,之后用DP才干够的.

详细看代码:

暴力法TLE:

public class Solution {
public boolean isScramble(String s1, String s2) {

if (s1 == null || s2 == null)
return false;
if (s1.equals(s2))
return true;
int len1 = s1.length();
int len2 = s2.length();
if (len1 != len2)
return false;
int[] hash = new int[26];
for (int i=0; i<len1; ++i){
hash[s1.charAt(i) - 'a']++;
}
for (int i=0; i<len2; ++i){
hash[s2.charAt(i) - 'a']--;
}
for (int i=0; i<26; ++i){
if (hash[i] != 0)
return false;
}

for (int i=1; i<len1; ++i){
boolean flags1 = (isScramble(s1.substring(0,i), s2.substring(0,i)) && isScramble(s1.substring(i,len1), s2.substring(i,len2)));
boolean flags2 = (isScramble(s1.substring(0,i), s2.substring(len2-i,len2)) && isScramble(s1.substring(i,len1), s2.substring(0,len2-i)));
if (flags1 && flags2){
return true;
}
}
return false;
}
}


DP动态规划:

设数组flags[len][len][len]来存储每个状态信息.

如flags[i][j][k] 表示s1字符串的第i个位置開始的k个字符和s2字符串的第j个位置開始的k个字符 是否满足scramble string

满足:flags[i][j][k] == true

不满足: flags[i][j][k] == false

那么题目所要的终于结果的值事实上就相当于是flags[0][0][len]的值了

那么状态转移方程是什么呢?

归纳总结法

假设k==1:

flags[i][j][1] 就相当于 s1的第i个位置起,取1个字符。s2的第j个位置起,取1个字符。那假设要使Scramble String成立的话,那么就仅仅能是这两个字符相等了, s1.charAt(i) == s2.charAt(j)

因此 flags[i][j][1] = s1.charAt(i) == s2.charAt(j);

假设k==2:

flags[i][j][2] 就相当于 s1的第i个位置起,取2个字符。s2的第j个位置起,取2个字符。那假设要使Scramble String成立的话,那么情况有下面两种

一种是flags[i][j][1] && flags[i+1][j+1][1] (就是两个位置的字符都相等 S1="TM" S2="TM")

一种是flags[i][j+1][1] && flags[i+1][j][1] (两个位置的字符刚好对调位置 S1="TM" S2="MT")

假设k==n:

设个变量为x

flags[i][j]
=( (flags[i][j][x] && flags[i+x][j+x][k-x]) [第一种情况]

|| (flags[i][j+k-x][x] && flags[i+x][j][k-x]) ); [另外一种情况]

AC代码:

public class Solution {
public boolean isScramble(String s1, String s2) {

if (s1 == null || s2 == null)
return false;
if (s1.equals(s2))
return true;
int len1 = s1.length();
int len2 = s2.length();
if (len1 != len2)
return false;
int len = len1;
boolean[][][] flags= new boolean[len+1][len+1][len+1];
for (int t=1; t<=len; ++t){
for (int i=0; i<=len-t; ++i){
for (int j=0; j<=len-t; ++j){
if (t == 1){
flags[i][j][t] = (s1.charAt(i) == s2.charAt(j));
}else{
for (int k=1; k<t; ++k){
if (flags[i][j][t] == true){
break;
}else{
if ((flags[i][j][k] && flags[i+k][j+k][t-k])
|| (flags[i][j+t-k][k] && flags[i+k][j][t-k])){
flags[i][j][t] = true;
}
}
}
}
}
}
}
return flags[0][0][len];
}
}


题目四:

Rotate List



Given a list, rotate the list to the right by k places, where k is non-negative.

For example:

Given
1->2->3->4->5->NULL
and k =
2
,

return
4->5->1->2->3->NULL
.

分析:

题意要求我们依据所给出的k值,把从最后一个非空结点向前的k个结点移动到链表的开头,又一次组成一个新的链表之后返回。

这道题目有点像经典的面试题“仅仅遍历一次,怎样找到链表倒数的第K个结点”,採用的是两个指针不一样的起始位置,一个指针从head開始出发,还有一个指针先让它走K步,当第2个指针为Null的时候,则第一个指针所指向的就是倒数第K个的值。

同理:

这里我们用两个指针就能够方便地搞定这个题目了,可是须要注意的是,这道题目

假设K大于了链表长度,比方K=3,Len=2的话,假设K步我们还没走完就碰到了Null结点,那么再从head開始走剩下的。直到K==0;

AC代码:

/**
* Definition for singly-linked list.
* public class ListNode {
*     int val;
*     ListNode next;
*     ListNode(int x) {
*         val = x;
*         next = null;
*     }
* }
*/
public class Solution {
public ListNode rotateRight(ListNode head, int n) {
ListNode firstNode = head;//新链表的第一个结点
ListNode kstepNode = head;//走了k步的指针
ListNode preFirstNode = new ListNode(-1);//新链表第一个结点的前一个结点
ListNode preKstepNode = new ListNode(-1);//k步指针的前一个结点

if (head == null || n == 0){
return head;
}
int k = n;

//先走K步
while (k != 0){
//假设走到链表结束了k还不为0,那么再回到head头结点来继续
if (kstepNode == null){
kstepNode = head;
}
kstepNode = kstepNode.next;
k--;
}
//假设刚好走到链表结束,那么就不用再处理了,当前的链表就满足题意了
if (kstepNode == null){
return firstNode;
}
//处理两个结点同一时候走,知道第二个指针走到Null,则第一个指针是倒数第K个结点
while (kstepNode != null){
preFirstNode = firstNode;
firstNode = firstNode.next;

preKstepNode = kstepNode;
kstepNode = kstepNode.next;
}
preKstepNode.next = head;
preFirstNode.next = null;

return firstNode;
}
}


题目五:Partition List

Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.

You should preserve the original relative order of the nodes in each of the two partitions.

For example,

Given
1->4->3->2->5->2
and x = 3,

return
1->2->2->4->3->5
.

分析:

妈蛋,英文题目看着就是蛋疼,看了好久才理解它的题意:

题目要求我们说给出一个X的值,你要把全部的 小于X的值的结点放在全部大于或等于X的值的前面,关键这里X又等于3,跟题目里面给出的链表中当中一个结点的值一样,迷惑了。

一旦题意明确了,剩下的就好办了,竟然这种话,那我们仅仅须要先找出第一个 “大于或等于X值”的结点,并记录下它的位置。

然后剩下的仅仅要遍历一次链表,把小于X的插入到它的前面,大于或等于X 不变位置(由于我们这里找到的是第一个“大于或等于X值”的结点)。

AC代码:

/**
* Definition for singly-linked list.
* public class ListNode {
*     int val;
*     ListNode next;
*     ListNode(int x) {
*         val = x;
*         next = null;
*     }
* }
*/
public class Solution {
public ListNode partition(ListNode head, int x) {
ListNode firstNode = head;
ListNode preFirstNode = new ListNode(-1);
preFirstNode.next = firstNode;
ListNode tempNode = head;
ListNode pretempNode = new ListNode(-1);
pretempNode.next = tempNode;
ListNode preHead = new ListNode(-1);
preHead.next = head;

int index = 0;
//find the first (>= x)'s node
while (firstNode != null){
if (firstNode.val >= x){
break;
}else{
preFirstNode = firstNode;
firstNode = firstNode.next;
index++;//记录位置
}
}
//假设第一个满足条件的结点是头结点
if (firstNode == head){
preHead = preFirstNode;
}
//取得当前下标,假设在第一个满足条件的结点之前则不处理
int p = 0;
while (tempNode != null){
if (tempNode != firstNode){
//值小于x,而且在第一个满足条件结点之后。
if (tempNode.val < x && p > index){
/*做移动*/
pretempNode.next = tempNode.next;
tempNode.next = preFirstNode.next;
preFirstNode.next = tempNode;
preFirstNode = tempNode;
tempNode = pretempNode.next;
index++;
p++;
continue;
}
}
pretempNode = tempNode;
tempNode = tempNode.next;
p++;
}

return preHead.next;

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: