25.复杂链表的复制
题目描述:输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空) 解题思路: 1.遍历链表,复制每个结点,如复制结点A得到A1,将结点A1插到结点A后面; 2.重新遍历链表,复制老结点的随机指针给新结点,如A1.random = A.random.next; 3.拆分链表,将链表拆分为原链表和复制后的链表
public class Clone {
public RandomListNode Clone(RandomListNode pHead) {
if(pHead == null) {
return null;
}
RandomListNode currentNode = pHead;
//1、复制每个结点,如复制结点A得到A1,将结点A1插到结点A后面;
while(currentNode != null){
RandomListNode cloneNode = new RandomListNode(currentNode.label);
RandomListNode nextNode = currentNode.next;
currentNode.next = cloneNode;
cloneNode.next = nextNode;
currentNode = nextNode;
}
currentNode = pHead;
//2、重新遍历链表,复制老结点的随机指针给新结点,如A1.random = A.random.next;
while(currentNode != null) {
currentNode.next.random = currentNode.random==null?null:currentNode.random.next;
currentNode = currentNode.next.next;
}
//3、拆分链表,将链表拆分为原链表和复制后的链表
currentNode = pHead;
RandomListNode pCloneHead = pHead.next;
while(currentNode != null) {
RandomListNode cloneNode = currentNode.next;
currentNode.next = cloneNode.next;
cloneNode.next = cloneNode.next==null?null:cloneNode.next.next;
currentNode = currentNode.next;
}
return pCloneHead;
}
}
26.二叉搜索树与双向链表
题目描述:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
public class Convert {
public TreeNode Convert(TreeNode pRootOfTree) {
if (pRootOfTree == null){
return null;
}
TreeNode list = null;
Stack<TreeNode> stack = new Stack<>();
while (pRootOfTree != null || !stack.isEmpty()){
if (pRootOfTree != null){
stack.push(pRootOfTree);
pRootOfTree = pRootOfTree.right;
}else{
pRootOfTree = stack.pop();
if (list == null){
list = pRootOfTree;
}else{
list.left = pRootOfTree;
pRootOfTree.right = list;
list = pRootOfTree;
}
pRootOfTree = pRootOfTree.left;
}
}
return list;
}
}
27.字符串的排列
题目描述:输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 输入描述:输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。 解题思路:
解析:http://www.cnblogs.com/cxjchen/p/3932949.html (感谢该文作者!) 对于无重复值的情况 固定第一个字符,递归取得首位后面的各种字符串组合; 再把第一个字符与后面每一个字符交换,并同样递归获得首位后面的字符串组合; *递归的出口,就是只剩一个字符的时候,递归的循环过程,就是从每个子串的第二个字符开始依次与第一个字符交换,然后继续处理子串。 假如有重复值呢? *由于全排列就是从第一个数字起,每个数分别与它后面的数字交换,我们先尝试加个这样的判断——如果一个数与后面的数字相同那么这两个数就不交换了。 例如abb,第一个数与后面两个数交换得bab,bba。然后abb中第二个数和第三个数相同,就不用交换了。 但是对bab,第二个数和第三个数不 同,则需要交换,得到bba。 由于这里的bba和开始第一个数与第三个数交换的结果相同了,因此这个方法不行。 换种思维,对abb,第一个数a与第二个数b交换得到bab,然后考虑第一个数与第三个数交换,此时由于第三个数等于第二个数, 所以第一个数就不再用与第三个数交换了。再考虑bab,它的第二个数与第三个数交换可以解决bba。此时全排列生成完毕!
public ArrayList<String> Permutation(String str){
ArrayList<String> list = new ArrayList<String>();
if(str!=null && str.length()>0){
PermutationHelper(str.toCharArray(),0,list);
Collections.sort(list);
}
return list;
}
private void PermutationHelper(char[] chars,int i,ArrayList<String> list){
if(i == chars.length-1){
list.add(String.valueOf(chars));
}else{
Set<Character> charSet = new HashSet<Character>();
for(int j=i;j<chars.length;++j){
if(j==i || !charSet.contains(chars[j])){
charSet.add(chars[j]);
swap(chars,i,j);
PermutationHelper(chars,i+1,list);
swap(chars,j,i);
}
}
}
}
private void swap(char[] cs,int i,int j){
char temp = cs[i];
cs[i] = cs[j];
cs[j] = temp;
}
28.数组中出现次数超过一半的数字
题目描述:数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。 解题思路:用Map存储每个数字出现的次数。
public int MoreThanHalfNum_Solution(int [] array) {
Map<Integer,Integer> map = new HashMap<Integer, Integer>();
for (int i = 0; i < array.length ; i++) {
if(!map.containsKey(array[i])){
map.put(array[i],1);
}else {
map.put(array[i],(map.get(array[i])+1));
}
}
for (int i = 0 ; i <(array.length / 2 + 1) ;i ++){
if (map.get(array[i]) > (array.length / 2)){
return array[i];
}
}
return 0;
}
29.最小的K个数
题目描述:输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。 解题思路:排序,返回序列。
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> result = new ArrayList<>();
if (k > input.length){
return result;
}
for (int i = 0; i < input.length - 1 ; i++) {
for (int j = i + 1; j < input.length ; j++) {
if (input[i] > input[j]){
int num = input[i];
input[i] = input[j];
input[j] = num;
}
}
}
for (int i = 0; i < k ; i++) {
result.add(input[i]);
}
return result;
}
30.连续子数组的最大和
题目描述:HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1) 解题思路:双重for循环遍历数组求和即可。
public int FindGreatestSumOfSubArray(int[] array) {
int max = -999999;
for (int i = 0; i < array.length - 1 ; i++) {
int sum = 0;
for (int j = i; j < array.length;j++){
sum = sum + array[j];
if(sum > max){
max = sum;
}
}
}
return max;
}