原题连接
- 第一题:调整数组顺序使奇数位于偶数前
- 第二题:链表中倒数第K个结点
- 第三题:反转链表
- 第四题:合并两个排序的链表
- 第五题:树的子结构
- 第六题:二叉树的镜像
1.调整数组顺序使奇数位于偶数前
题目描述
输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
思路1
两个思路,第一个是仿冒泡排序,遍历数组,前一个是偶数,后一个数是奇数,就交换,也就是前偶后奇就交换
时间复杂度:O(n^2)
空间复杂度:O(1)
public void reOrderArray(int [] array) {
//前偶后奇就交换
if (array.length ==0)
return;
for (int i = 0; i < array.length; i++) {
for (int j = array.length-1; j > i; j--) {
if ((array[j] & 1) !=0 && (array[j-1] & 1) ==0){
int temp = array[j];
array[j] =array[j-1];
array[j-1] = temp;
}
}
}
}
思路2
可以采用辅助数组的形式,建立一个和原数组等长的辅助数组,遍历原数组,遇见奇数就放从0开始放,遇见偶数就从奇数的末尾开始放
时间复杂度:O(n)
空间复杂度:O(n)
public void reOrderArray(int [] array) {
int[] newArray = new int[array.length];
int oddCount = 0;
int oddBegin = 0;
for (int i = 0; i < array.length; i++) {
if ((array[i] & 1) != 0)
oddCount++;
}
for (int i = 0; i < array.length; i++) {
if ((array[i] & 1) != 0) {
newArray[oddBegin++] = array[i];
} else {
newArray[oddCount++] = array[i];
}
}
for (int i = 0; i < array.length; i++) {
array[i] = newArray[i];
}
}
扩展
如果把后面的条件就是“奇数和奇数,偶数和偶数的相对位置不变”去掉,这就是原微软的面试题,这里也说下思路和代码
思路就是遍历这个数组,一个从头开始,向后移动,直到找到第一个偶数,一个从尾开始,向前移动找到第一个奇数开始,交换这两个数,重复过程,直到两个指针相等为止
public void reOrderArray3(int[] array) {
int beginIndex = 0;
int endIndex = array.length - 1;
while (beginIndex < endIndex) {
while (beginIndex < endIndex && (array[beginIndex] & 1) != 0)
beginIndex++;
while (beginIndex < endIndex && (array[endIndex] & 1) == 0)
endIndex--;
if (beginIndex < endIndex) {
int temp = array[beginIndex];
array[beginIndex] = array[endIndex];
array[endIndex] = temp;
}
}
}
2.链表中的倒数第K个结点
题目描述
输入一个链表,输出该链表中倒数第k个结点
思路
前后指针法,就是第一个指针先走k步,然后第二个指针再从链表的头指针开始走,这样当第一个指针走到链表的尾节点时候,第二个指针刚好走到倒数第k个节点。
要注意链表的节点总数不能少于k个
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public ListNode FindKthToTail(ListNode head, int k) {
if (head == null || k == 0)
return null;
ListNode begin = head;
ListNode behind;
for (int i = 0; i < k; i++) {
if (head.next != null) {
begin = begin.next;
} else {
return null;
}
}
behind = head;
while (begin.next != null) {
behind = behind.next;
begin = begin.next;
}
return behind;
}
扩展
求链表的中间节点。如果链表中的节点总数为奇数,则返回中间节点的;如果是偶数,则返回中间两个节点的其中一个就行
同样也可以使用两个指针,同时从链表的头节点出发,第一个指针一次走一步,第二个指针一次走两步,这样当第二个指针到达链表的尾节点的时候,第一个指针正好走在链表的中间节点处。
3.反转链表
题目描述
输入一个链表,反转链表后,输出新链表的表头。
思路
有两种做法,第一种就是递归,就是把头节点后面的链表都反转过来,然后把头节点接到最后
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}
public ListNode ReverseList(ListNode head) {
if (head == null || head.next == null)
return head;
ListNode pre =ReverseList(head.next);
head.next.next=head;
head.next=null;
return pre;
}
第二种思路就是非递归,如果要反转一个链表,就需要知道这个链表当前遍历到的节点,它的前一个和后一个节点。
public ListNode ReverseList2(ListNode head) {
ListNode reverseHead = null;
ListNode node = head;
ListNode prev = null;
while (node != null) {
ListNode next = node.next;
if (next == null)
reverseHead = node;
node.next = prev;
prev = node;
node = next;
}
return reverseHead;
}
4.合并两个排序的链表
题目描述
输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。
思路
也是一样有两种解法,一种递归一种非递归,就是去比较这两个链表头节点,哪个值小返回哪个值,然后合并链表,以此比较
//递归
public ListNode Merge(ListNode list1,ListNode list2) {
if (list1 == null)
return list2;
if (list2==null)
return list1;
if (list1.val < list2.val){
list1.next = Merge(list1.next,list2);
return list1;
} else{
list2.next = Merge(list1,list2.next);
return list2;
}
}
5.树的子结构
题目描述
输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)
思路
先判断B是不是A的子结构,再判断B是不是A左子树的子结构,然后再判断是B是不是A右字数的子结构
public boolean HasSubtree(TreeNode root1, TreeNode root2) {
boolean result = false;
if (root1 != null && root2 != null) {
if (root1.val == root2.val)
result = isSubTree(root1,root2);
if (!result)
result = HasSubtree(root1.left,root2);
if (!result)
result = HasSubtree(root1.right,root2);
}
return result;
}
private boolean isSubTree(TreeNode root1, TreeNode root2){
if (root2 == null)
return true;
if (root1 ==null && root2 !=null)
return false;
if (root1.val == root2.val){
return isSubTree(root1.left,root2.left) && isSubTree(root1.right,root2.right);
}else{
return false;
}
}
6.二叉树的镜像
题目描述
操作给定的二叉树,将其变换为源二叉树的镜像。
思路
将根节点的左右子树节点都转换成镜像,然后把叶子节点的值交换
public void Mirror(TreeNode root) {
if (root == null)
return;
Mirror(root.left);
Mirror(root.right);
TreeNode temp = root.left;
root.left = root.right;
root.right= temp;
}