Lebi's blog

这个人很懒,什么都没留下


  • Home

  • Categories

  • Archives

  • Tags

Reverse Nodes in k-Group

Posted on 2016-06-17

Reverse Nodes in k-Group

Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.
If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.
You may not alter the values in the nodes, only nodes itself may be changed.
Only constant memory is allowed.
For example,
Given this linked list: 1->2->3->4->5
For k = 2, you should return: 2->1->4->3->5
For k = 3, you should return: 3->2->1->4->5

题意

给定一个链表和一个值k,使链表以k为宽度进行反转,小于k的部分进行保留。在变换过程中不能修改节点的值,且只能使用常量的内存空间。
例如:输入链表1->2->3->4->5
如果k=2,需要返回2->1->4->3->5
如果k=3,需要返回3->2->1->4->5

解题思路

这道题主要就是考察对于链表的操作,而且只能使用固定的内存空间,因此就是对链表进行遍历,每次遍历k个节点,将节点进行反转,然后将这部分链表的头节点指向下一部分链表的末尾。如果出现剩余节点小于k的情况,就需要调整头节点指向下部分链表的开头。
例如1->2->3->4->5,k=2
1.先定位头节点到2,这个节点将作为返回值
2.将1->2进行翻转,翻转完成后向后遍历k个,如果能够遍历完k个,到第3步,否则到第4步
3.将当前部分的头节点的next指向下一部分的末节点,即将1的next指向4,然后将当前的头移到下一部分的头节点即3这个位置。然后重复2,3两步
4.此时剩余的节点个数小于k个,那么需要将当前部分的头节点的next指向下一部分的头,即将3的next指向5,然后返回head

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
 public ListNode reverseKGroup(ListNode head, int k) {
if(k==1||head==null)return head;
ListNode start=head,end=head,next,it,itnext,itprev;
it=head;
for(int i=0;i<k-1;i++){
it=it.next;
if(it==null)return head;
}
head=it;
end=head;
while(true){
itprev=start;
it=start.next;
next=end.next;
for(int i=0;i<k-1;i++){
itnext=it.next;
it.next=itprev;
itprev=it;
it=itnext;
}
end=next;
for(int i=0;i<k-1;i++){
if(end==null||end.next==null) {
start.next=next;
return head;
}
end=end.next;
}
start.next=end;
start=next;
}
}

Substring with Concatenation of All Words

Posted on 2016-06-16

Leetcode:Substring with Concatenation of All Words

You are given a string, s, and a list of words, words, that are all of the same length. Find all starting indices of substring(s) in s that is a concatenation of each word in words exactly once and without any intervening characters.
For example, given:
s: “barfoothefoobarman”
words: [“foo”, “bar”]
You should return the indices: [0,9].
(order does not matter).

题意

输入一个字符串s和一个字母等长的字符串数组words,在s中找到一个由words中所有单词组成的子串的起始位置,且words的单词只在子串中出现一次,并且中间也没有插入其他字符。
输入: s:”barfoothefoobarman”和words:[“foo”, “bar”]
s中符合条件的子串为barfoo和foobar,这两个子串的初始下标分别为0和9。

解题思路

  题目中有一个很重要的点就是words中的单词都是等长的,针对这一点,从s串中截取一定长度的串,以map作为辅助检查这个子串是不是符合条件的串。按照这个思路写完代码后发现会超时,因为其中包含了太多的多余比较,例如示例中比较到第三个位置即foothe时,此时已知the已经不包含在words中,只要包含the的都一定不符合条件,希望直接能跳到第9的位置来比较foobar。
优化思路:
  截取到子串后将其从后到前比较,如果检查到有不符合条件的单词,那么之前的单词也一定不符合条件,可以直接将前一个检查点作为截取字符串的开头:在检查到thefoo时,从后到前检比较,foo符合,the不符合,就直接从foo位置开始继续检查。
注意:
  为了确保没有遗漏,还需要对字符串进行移位检查,移位范围为单词的长度。例如”aaa·aaa·b”和[“aa”,”aa”,”ab”],在检查完0-6子串后,还需要检查1-7子串,两次检查较小值作为下次截取字符串的开头。
  代码在leetcode上提交后运行速度在前5%左右。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
public class Solution {
List<Integer> res=new ArrayList<Integer>();
Map<String, Integer> mem=new HashMap<>();
int len;
public List<Integer> findSubstring(String s, String[] words) {
if(words.length==0)
return res;
len=words[0].length()*words.length;
for(String i:words){
if(mem.containsKey(i))
mem.put(i, mem.get(i)+1);
else
mem.put(i, 1);
}
int pos=0;
while(true){
pos=find(s,pos,words);
if(pos+len>s.length()){
return res;
}
}
}

int find(String s,int index,String[] words){
Map<String, Integer> map=new HashMap<>();
int clen=words[0].length();
//min是函数返回值,代表下次截取字符串的开头位置
int min=len+index;
//移位检查
for(int i=0;i<clen;i++){
map.clear();
for(int j=words.length-1;j>=0;j--){
//left从后往前,index表示字符串开头,i表示偏移
int left=index+i+j*clen,right=left+clen;
if(right>s.length())
return min;
String str=s.substring(left,right);
if(!mem.containsKey(str)){
//min的值取比较较小值
min=Math.min(min, right);
break;
}
if(!map.containsKey(str))
map.put(str, 1);
else
map.put(str, map.get(str)+1);
if(mem.get(str)<map.get(str)){
min=Math.min(min, right);
break;
}
if(j==0){
res.add(index+i);
//如果成功匹配,那么后移一个单词
min=Math.min(index+clen, min);
}
}
}
return min;
}
}

Merge k Sorted Lists

Posted on 2016-06-16

Leetcode: Merge k Sorted Lists

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

题意

将k个有序链表合并成一个有序链表,分析算法的复杂度。

集体思路

对于k个有序链表的合并,使用分而治之的思路,先让两个链表合并得到一个新链表,再将新链表进行合并。算法的时间复杂度是log(k)*(k*n),n表示链表长度的平均值。空间复杂度为O(1)。提交后在leetcode上运行时间在前30%。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode(int x) { val = x; }
* }
*/

public class Solution {
public ListNode mergeKLists(ListNode[] lists) {
return merge(lists,0,lists.length-1);
}

public ListNode merge(ListNode[] lists,int a,int b){
if(lists.length==0) return null;
if(a<b){
int mid=(a+b)/2;
ListNode l1=merge(lists,a,mid);
ListNode l2=merge(lists,mid+1,b);
return mergerTwo(l1,l2);
}else
return lists[a];
}

public ListNode mergerTwo(ListNode l1,ListNode l2){
ListNode head=new ListNode(0);
ListNode it=head;
while(l1!=null&&l2!=null){
int min;
if(l1.val>l2.val){
min=l2.val;
l2=l2.next;
}else{
min=l1.val;
l1=l1.next;
}
it.next=new ListNode(min);
it=it.next;
}
while(l1!=null){
it.next=new ListNode(l1.val);
l1=l1.next;
it=it.next;
}

while(l2!=null){
it.next=new ListNode(l2.val);
l2=l2.next;
it=it.next;
}
return head.next;
}
}

饥荒独立服务器搭建

Posted on 2016-06-14

Don’t starve together 独立服务器搭建指南

  在和朋友一起玩Don’t starve together的时候发现游戏玩到后期总是会变的非常不流畅,经过测试后排除网络问题,主要是因为联机玩DST时创建世界的那台主机因为需要同时处理画面和世界的刷新,玩到后期主机要处理的太多,其他联机的用户就会卡顿。为了解决这个问题我也是头疼了很久,最后发现在主机上搭建一个独立服务器,所有人都再连接到这个独立服务器上,卡顿问题就能很好的解决了。当然这个独立服务器并不需要一台独立的电脑,只需要一起玩游戏的某个人开一个独立服务器,大家再连接到这个独立服务器里,就不会卡顿了。

Windows搭建全过程

1.购买DST的正版

2.创建世界

  首先打开饥荒,先创建一个世界,选择好mod,创建的选项等,然后点创建世界,等待世界创建成功后断开世界。需要记住你创建的这个世界是第几个存档,如图例子就是第三个存档。

3.配置

  在世界创建成功后,就能在在目录“文档/Klei/DoNotStarveTogether/Cluster_3”(对应你创建的第几个存档),这个目录下看到几个文件:包括Master(主世界数据),Caves(洞穴实际数据,如果选择添加洞穴的话),cluster.ini(世界的配置文件)。然后需要在这个目录中添加一个文件叫cluster_token.txt,下面介绍在这个文件中需要写入什么东西。
  进入DST后的这个页面,点击下面的个人资料

  出现下面这个页面,点击generate server token按钮,将上面出现的token复制到cluster_token.txt中,就可以了。如果没这一步在创建世界的时候会出错,估计是Klei对防盗版的一个限制。

4.创建脚本

  将上述准备工作做完后,就进入最后一步,创建启动脚本和启动服务器了。进入steam的安装目录,进入steamapps/common/Don’t Starve Together/bin,可以看到一个dontstarve_dedicated_server_nullrenderer.exe这个文件,从这个应用程序的名字就可以知道,就需要通过他来创建一个无画面的服务器。
  创建一个文件start.bat,在里面写入

1
dontstarve_dedicated_server_nullrenderer -console -cluster Cluster_3 -shard Master

  当然Cluster_3这里改成你对应的存档,然后创建一个文件start_cave.bat,在里面写入

1
dontstarve_dedicated_server_nullrenderer -console -cluster Cluster_3 -shard Caves

  写完后就将这两个脚本启动就可以了。

5.加入游戏

  选择浏览游戏,搜索创建的服务器名字(本机的话需要到LAN中才能找到世界),就能找到这个世界并加入游戏了,亲测玩到后期也一点都不卡哦。

Mac搭建全过程

1,2步同Windows

3.配置

  Mac的数据文件目录在”~/文稿/Klei/…”中,具体配置相同。

4.创建脚本

  Mac中饥荒的目录在”~/Library/Application Support/Steam/steamapps/common/Don’t Stave Together.app/MacOS”中有一个叫dontstarve_dedicated_server_nullrenderer的文件,同在这个目录下创建两个文件start.sh和start_cave.sh,分别写入

1
./dontstarve_dedicated_server_nullrenderer -console -cluster Cluster_3 -shard Master

1
./dontstarve_dedicated_server_nullrenderer -console -cluster Cluster_3 -shard Caves

最然后在命令行执行命令,使这两个文件变成可执行文件

1
2
chmod 777 start.sh
chmod 777 start_cave.sh

通过下面的命令启动两个脚本

1
2
./start.sh
./start_cave.sh

5.加入游戏

  加入游戏玩耍吧。

Regular Expression Matching

Posted on 2016-06-08

Leetcode: Regular Expression Matching

Implement regular expression matching with support for ‘.’ and ‘*’.

‘.’ Matches any single character.
‘‘ Matches zero or more of the preceding element.
The matching should cover the entire input string (not partial).The function prototype should be:bool isMatch(const char
s, const char p)
Some examples:
isMatch(“aa”,”a”) → false
isMatch(“aa”,”aa”) → true
isMatch(“aaa”,”aa”) → false
isMatch(“aa”, “a
“) → true
isMatch(“aa”, “.“) → true
isMatch(“ab”, “.
“) → true
isMatch(“aab”, “cab”) → true

题意

实现正则表达式中的’.’和’*’,输入两个字符串,返回是否匹配。

解题思路

  使用DFS的方法,主要思路就是例如当a*ab和aaab进行匹配时,第一个字符匹配且第二个字符为*,那么先令ab和aaab进行匹配。因为ab和aaab匹配失败,再回溯到之前,并将s串后移一位,即匹配a*ab和aab。使用递归,这就是一个很典型的DFS的实现。
  在实现时需要考虑几个特殊的测试用例:当s串为空;当p串为空。
  使用回溯的做法,当输入类似为a*aab和aaaab时,需要进行多次的回溯,时间复杂度是O(n!),最后算法在leetcode上提交约在50%。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
public boolean check(char[] s,int s1,char[] p,int p1){
int slen=s.length-s1,plen=p.length-p1;
//s串为空,例如''和'a*c'
if(slen==0){
if(plen%2!=0)
return false;
for(int i=p1+1;i<p.length;i+=2)
if(p[i]!='*')
return false;
return true;
}

if(plen==0)
return false;

if(plen==1)
if(slen==1&&(s[s1]==p[p1]||p[p1]=='.'))
return true;
else
return false;

if(p[p1+1]!='*'){
if(p[p1]=='.'||p[p1]==s[s1])
return check(s,s1+1, p,p1+1);
else return false;
}
if(p[p1]=='.'||p[p1]==s[s1])
if(check(s, s1,p,p1+2))
return true;
else
return check(s,s1+1, p,p1);
else
return check(s,s1, p,p1+2);
}
public boolean isMatch(String s, String p) {
return check(s.toCharArray(),0,p.toCharArray(),0);
}

Median of Two Sorted Arrays

Posted on 2016-06-07

Leetcode: Median of Two Sorted Arrays

There are two sorted arrays nums1 and nums2 of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

题意

两个排序好的数组num1和num2的大小分别为m和n,找到数组的中位数,算法整体时间复杂度应该为O(log (m+n))。

解题思路

方法1

  找到两个排序数组的中位数,非常容易想到的方法就是遍历两个数组,从小到大的寻找。因为是中位数,可能出现在两个数之间,所以使用一个长度为(m+n)/2+1的数组保存遍历的数,最后直接取对应位置的数即可。
  这种方法的思路很简单,但是在效率上不高,虽然时间复杂度还是O(log (m+n)),但是其实存在很多不必要的比较,因为已经知道需要寻找的是第几个数了,最后在leetcode上运行时间为7ms,仅超过5%的提交。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m=nums1.length,n=nums2.length;

int all=m+n;
int[] arr=new int[all/2+1];
int m1=0,n1=0,i=0;

while(i<arr.length){
if(m1==nums1.length)
arr[i++]=nums2[n1++];
else if(n1==nums2.length)
arr[i++]=nums1[m1++];
else{
if(nums1[m1]>nums2[n1])
arr[i++]=nums2[n1++];
else
arr[i++]=nums1[m1++];
}
}

if(all==1)
return arr[0];
if(all%2==0)
return (arr[all/2-1]+arr[all/2])/2.0;
else
return arr[all/2];
}

方法2

  还有一种使用参考二分法的做法来解这题。
  对于两个长度为m和n的数组,从中找到第k小的数,取M[k/2]和N[k/2]两个数做比较,如果M[k/2]较大,那么目标在N[k/2]之后,继续在两个长度为m和n-k/2的数组中寻找第k/2小的数,反之亦然。如果取第i(i>k/2)个数比较M[i]和N[i],即使M[i]>N[i],那么目标数也可能会出现在n[i]之前。
  在实现过程中还要考虑如果数组长度n小于k/2的时候,那就应该用n代替k/2。
  最后在leetcode上提交运行时间为5ms,与大部分提交时间相同。

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public int find(int[] arr1,int s1,int m,int[] arr2,int s2,int n,int k){
int r1=m-s1;
int r2=n-s2;
//比较数组剩余长度,使arr2小于arr1
if(r1<r2)
return find(arr2, s2, n,arr1,s1,m, k);
if(r2==0)
return arr1[k+s1-1];
if(k==1)
return Math.min(arr1[s1], arr2[s2]);

//arr2的向后移动距离
int p2=Math.min(k/2, r2);
int p1=k-p2;

if(arr1[p1+s1-1]>arr2[p2+s2-1])
//arr1较大,arr2向后移动
return find(arr1,s1,m,arr2,s2+p2,n,k-p2);
else if(arr1[p1+s1-1]<arr2[p2+s2-1])
//反之,arr1向后移动
return find(arr1,s1+p1,m,arr2,s2,n,k-p1);
return arr1[p1+s1-1];
}

public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m=nums1.length;
int n=nums2.length;

int all=m+n;
if(all%2==0){
return (find(nums1,0,m,nums2,0,n,all/2)+find(nums1,0,m,nums2,0,n,all/2+1))/2.0;
}else
return find(nums1,0,m,nums2,0,n,all/2+1);
}

Hello World

Posted on 2016-06-07

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

Lebi

Lebi

7 posts
2 tags
© 2016 Lebi
Powered by Hexo
Theme - NexT.Muse