@剑指offer题解整理
旋转之后的数组实际上可以划分成两个有序的子数组:前面子数组的大小都大于后面子数组中的元素。注意到实际上最小的元素就是两个子数组的分界线。本题目给出的数组一定程度上是排序的,因此我们试着用二分查找法寻找这个最小的元素。
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length == 0 && array == null){
return -1;
}
int frist = 0;
int last = array.length - 1;
int mid ;
while(last != frist+1){
mid = (last + frist)/2;
if(array[mid] >= array[frist]){
frist = mid;
}else if (array[mid] <= array[last]){
last = mid;
}
}
return array[last];
}
}
如果原数组是一个非减数组
import java.util.ArrayList;
public class Solution {
public int minNumberInRotateArray(int [] array) {
if(array.length == 0){
return 0;
}
int index1 = 0;
int index2 = array.length-1;
if(array[index1]<array[index2]){
return array[index1];
}
int mid = (index2+index1)/2;
if(array[index1]==array[index2]||array[index1]==array[mid]||array[mid]==array[index2]){
for(int i = 0;i<array.length-1;i++){
if(array[i]>array[i+1]){
return array[i+1];
}else{
if(i==array.length-2){
if(array[i]<array[array.length-1]){
return array[0];
}
}
}
}
}
while(true){
mid = (index1+index2)/2;
if(array[mid]<array[index2]){
index2=mid;
}else{
index1=mid+1;
}
if(index1==index2){
return array[index1];
}
}
}
}
题目:输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。
public class Solution {
public void reOrderArray(int[] array) {
int[] arr = new int[array.length];
int i=0,k=0;
while(i<array.length){
if(array[i]%2 == 1 ){
arr[k++] = array[i];
}
i++;
}
i = 0;
while(i<array.length){
if(array[i]%2 == 0){
arr[k++] = array[i];
}
array[i] = arr[i];
i++;
}
}
}
public class Solution {
public void reOrderArray(int [] array) {
//相对位置不变,稳定性
//插入排序的思想
int m = array.length;
int k = 0;//记录已经摆好位置的奇数的个数
for (int i = 0; i < m; i++) {
if (array[i] % 2 == 1) {
int j = i;
while (j > k) {//j >= k+1
int tmp = array[j];
array[j] = array[j-1];
array[j-1] = tmp;
j--;
}
k++;
}
}
}
}
class Solution {
public:
void reOrderArray(vector<int> &array) {
for (int i = 0; i < array.size();i++){
for (int j = array.size() - 1; j>i;j--){
if (array[j] % 2 == 1 && array[j - 1]%2 == 0) { //前偶后奇交换
swap(array[j], array[j-1]);
}
}
}
}
};
import java.util.Stack;
/*
思路:建立一个栈,将链表中所有的结点全部push到栈中,需要倒数第k个结点,就从栈中弹出k个。
*/
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
if(head == null || k<=0){
return null;
}
Stack<ListNode> stack = new Stack();
ListNode crr = head;
int size = 0;//记录链表长度
while(true){
if(crr == null){
break;
}
stack.push(crr);
size++;
crr = crr.next;
}
ListNode kTh = null;
if(k <= size){//判断链表长度与K的关系,防止越界
for(int i = 1;i <= k;i++){
if(i==k){
kTh = stack.peek();
}
stack.pop();
}
}
return kTh;
}
public class Solution {
public ListNode FindKthToTail(ListNode head,int k) {
if(head==null||k<=0){
return null;
}
ListNode pre=head;
ListNode last=head;
for(int i=1;i<k;i++){
if(pre.next!=null){
pre=pre.next;
}else{
return null;
}
}
while(pre.next!=null){
pre = pre.next;
last=last.next;
}
return last;
}
}
还有一个简洁版的:思想是一样的。
public ListNode FindKthToTail12(ListNode head, int k) {
if(head==null||k<=0){
return null;
}
ListNode l = head;
while(head != null){
k--;
if(k < 0)
l = l.next;
head = head.next;
}
return k <= 0 ? l : null;
}
反转链表,切记,注意原链表的头结点的next是不是null。
public class Solution {
public ListNode ReverseList(ListNode head) {
if(head==null)
return null;
//head为当前节点,如果当前节点为空的话,那就什么也不做,直接返回null;
ListNode pre = null;
ListNode next = null;
//当前节点是head,pre为当前节点的前一节点,next为当前节点的下一节点
//需要pre和next的目的是让当前节点从pre->head->next1->next2变成pre<-head next1->next2
//即pre让节点可以反转所指方向,但反转之后如果不用next节点保存next1节点的话,此单链表就此断开了
//所以需要用到pre和next两个节点
//1->2->3->4->5
//1<-2<-3 4->5
while(head!=null){
//做循环,如果当前节点不为空的话,始终执行此循环,此循环的目的就是让当前节点从指向next到指向pre
//如此就可以做到反转链表的效果
//先用next保存head的下一个节点的信息,保证单链表不会因为失去head节点的原next节点而就此断裂
next = head.next;
//保存完next,就可以让head从指向next变成指向pre了,代码如下
head.next = pre;
//head指向pre后,就继续依次反转下一个节点
//让pre,head,next依次向后移动一个节点,继续下一次的指针反转
pre = head;
head = next;
}
//如果head为null的时候,pre就为最后一个节点了,但是链表已经反转完毕,pre就是反转后链表的第一个节点
//直接输出pre就是我们想要得到的反转后的链表
return pre;
}
}
public ListNode ReverseList(ListNode head) {
if(head == null){
return null;
}
ListNode pre = head;
ListNode crr = head.next;
ListNode next = crr.next;
while(pre.next != null){
if (next ==null){
crr.next = pre;
pre = crr;
break;
}
crr.next = pre;
pre = next.next;
next.next = crr;
crr = pre.next;
pre.next = next;
next = crr.next;
if (crr.next == null){
crr.next = pre;
pre = crr;
break;
}
if (next.next == null){
break;
}
}
return pre;
}
public ListNode ReverseList(ListNode head) {
if(head == null){
return null;
}
ListNode crr = head;
Stack<ListNode> stack = new Stack();
while(crr.next != null) {
stack.push(crr);
crr = crr.next;
}
ListNode reHead = crr;
while(!stack.empty()){
crr.next = stack.peek();
crr = crr.next;
stack.pop();
}
//将原链表头结点指向null
crr.next= null;
return reHead;
}
//非递归方法
/*
public class ListNode {
int val;
ListNode next = null;
ListNode(int val) {
this.val = val;
}
}*/
public class Solution {
public ListNode Merge(ListNode list1,ListNode list2) {
if(list1 == null && list2 == null){
return null;
}else if (list1 == null && list2 != null){
return list2;
}else if (list1 != null && list2 == null){
return list1;
}else{
//定义两个指针newHead用来确定合并后的头结点,crr通过他去合并两个链表
ListNode newHead = null;
ListNode crr = null;
while(list1 != null && list2 != null){
if(list1.val >= list2.val){
if(crr == null){
crr = list2;
newHead = crr;
}else{
crr.next = list2;
crr = crr.next;
}
list2 = list2.next;
}else{
if(crr == null){
crr = list1;
newHead = crr;
}else{
crr.next = list1;
crr = crr.next;
}
list1 = list1.next;
}
}
//因为两个链表都是递增的,所以遍历完任何一个,直接连接剩余部分。
if(list1 == null){
crr.next = list2;
}
if(list2 == null){
crr.next = list1;
}
return newHead;
}
}
}
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;
}
}
public class Solution {
public boolean hasPath(char[] matrix, int rows, int cols, char[] str){
if(matrix == null || rows<1 || cols<1 || str == null){
return false;
}
int strpath = 0;//已成功匹配字符个数
boolean[] path = new boolean[rows*cols];//布尔类型标志矩阵,初始化为false
//以二位数组遍历的方式去遍历数组,找到第一个符合位置的点。
for(int row = 0; row < rows;row++){
for(int col = 0; col< cols;col++){
if(hasPathCore(matrix,rows,cols,row,col,str,path,strpath)){
return true;
}
}
}
return false;
}
/**
* hasPathCore方法用来判断当前点是否能匹配str中的字符,如果能,递归其周围四个点。若不能弹回。
* @param matrix 初始矩阵
* @param rows 初始矩阵的行数
* @param cols 初始矩阵的列数
* @param row 当前行
* @param col 当前列
* @param str 目标矩阵
* @param path 标志矩阵
* @param strpath 成功匹配的个数
* @return hasPath 能否匹配当前字符
*/
private boolean hasPathCore(char[] matrix, int rows, int cols,int row,int col, char[] str,boolean[] path,int strpath){
if(strpath == str.length){
return true;
}
boolean hasPath =false;
if(row >= 0 && row<rows && col >= 0 && col < cols && matrix[row*cols+col] == str[strpath] && !path[row*cols+col]){
strpath++;
path[row*cols+col] = true;
hasPath = hasPathCore(matrix,rows,cols,row+1,col,str,path,strpath)
|| hasPathCore(matrix,rows,cols,row,col+1,str,path,strpath)
||hasPathCore(matrix,rows,cols,row-1,col,str,path,strpath)
||hasPathCore(matrix,rows,cols,row,col-1,str,path,strpath);
//回溯过程:
if(!hasPath){
strpath--;
path[row*cols+col] = false;
}
}
return hasPath;
}
}
public class Solution{
public int movingCount(int threshold, int rows, int cols)
{
if( rows < 0 || cols < 0){
return 0;
}
//为了避免出现重复,应该添加一个同样大小的标识型矩阵
boolean[][] flag = new boolean[rows][cols];
//定义一个记录机器人能够走多少个格子的变量;
int count = 0;
count = backMovingCount(threshold, rows, cols, 0, 0, count, flag);
return count;
}
/**
*
* @param threshold 阈值
* @param rows 矩阵行数
* @param cols 矩阵列数
* @param i 当前行数
* @param j 当前列数
* @param count 已走多少个格子
* @param flag 标识矩阵
* @return 当前走的格子数
*/
private int backMovingCount(int threshold, int rows, int cols,int i,int j,int count, boolean[][] flag){
if(i>=0 && i<rows && j>=0 && j<cols && indexSum(i)+indexSum(j) <= threshold && !flag[i][j]){
//用count来记录机器人走过的格子数,在递归的过程中要一直更新count值。
count++;
flag[i][j] = true;
count = backMovingCount( threshold, rows, cols, i+1, j, count, flag);
count = backMovingCount( threshold, rows, cols, i-1, j, count, flag);
count = backMovingCount( threshold, rows, cols, i, j+1, count, flag);
count = backMovingCount( threshold, rows, cols, i, j-1, count, flag);
}
return count;
}
private int indexSum(int i){
int sum = 0;
while(i/10 != 0 || i%10 != 0){
sum += (i%10);
i /= 10;
}
return sum;
}
}