剑指offer解题记录

面试题3:数组中重复的数字

题目链接

 

import java.util.Arrays;

/**
 * P39 面试题3:数组中重复的数字
 * 在一个长度为n的数组里所有数字都在0~n-1的范围内 数组中某些数字是重复的 但不知道有几个数字重复了
 * 也不知道每个数字重复了几次 请找出数组中任意一个重复的数字
 * 例如 如果输入长度为7的数组{2,3,1,0,2,5,3}
 * 那么对应的输出是重复的数字2或者3
 * @author tzy
 *
 */


public class T3
{
	public static void main(String[] args)
	{
		int[] duplication=new int[1];  //保存答案的数组 结果保存在[0]
		int[] inputarr={11,22,1,0,2,5,5};

		
	}
	
	/*
	 * 解法1:排序数组后找到重复值
	 * 排序算法的时间复杂度为O(nlogn)
	 */
	public static boolean solution1(int[] numbers,int length,int[] duplication)
	{
		if(numbers==null||length<=0)
		{
			return false;
		}
		Arrays.parallelSort(numbers);
		for(int i=0;i<numbers.length-1;i++)
		{
			if(numbers[i]==numbers[i+1])
			{
				duplication[0]=numbers[i];
				return true;
			}
		}
		return false;
	}
	
	/*
	 * 解法2:使用哈希表
	 * 时间复杂度O(N) 空间复杂度O(N)
	 */
	public static boolean solution2(int[] numbers,int length,int[] duplication)
	{
		int temp[]=new int[length+1];
		if(numbers==null||length<=0)
		{
			return false;
		}
		for(int i=0;i<length;i++)
		{
			temp[numbers[i]]++;
		}
		for(int j=0;j<length;j++)
		{
			if(temp[j]>1)
			{
				duplication[0]=j;
				return true;
			}
		}
		return false;
	}
	
	/*
	 * 解法3 推荐解法
	 * 时间复杂度O(N) 空间复杂度O(1)
	 * 通过将下标为i的数字(称为m)调整到属于它的下标的位置
	 */
	public static boolean solution3(int[] numbers,int length,int[] duplication)
	{
		if(numbers==null||length<=0)
		{
			return false;
		}
		for(int i=0;i<length;i++)
		{
			while(numbers[i]!=i)
			{
				if(numbers[i]==numbers[numbers[i]])
				{
					duplication[0]=numbers[i];
					return true;
				}
				int temp=numbers[i];
				numbers[i]=numbers[temp];
				numbers[temp]=temp;
			}
		}
		return false;
	}
}

面试题4:二维数组中的查找

题目链接

/*
 * P44面试题4:二维数组中的查找
 * 题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序
 * 请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数
 */
public class T4
{
	/*
	 * 思路:对于二维数组中的每一个数字,他小于他右边的数字,小于他下方的数字
	 * 所以从右上角的数字(称为m)开始查找 
	 * 若m>target 则剔除m所在的列 因为m是这一列最小的元素 这一列所有的元素将大于target
	 * 若m<target 则剔除m所在的行 因为m是这一行最小的元素 这一行所有的元素将小于target
	 */
	public boolean Find(int target, int [][] array) 
	{
		if(array.length==0||array[0].length==0||array==null)
		{
			return false;
		}
		//记录行数与列数
		int rows=array.length;
		int cols=array[0].length;
		//从右上角开始搜索
		int rownow=0;
		int colnow=cols-1;
		while(rownow<=rows-1&&colnow>=0)//搜索到最左下角的数字是边界条件
		{
			if(array[rownow][colnow]==target)
			{
				return true;
			}
			else if(array[rownow][colnow]>target)
			{
				colnow--;
			}
			else
			{
				rownow++;
			}
		}
		return false;
    }
}

面试题5:替换空格

题目链接

/*
 * P51面试题5:替换空格
 * 题目:请实现一个函数,把字符串中的每个空格替换成"%20"
 * 例如输入"We are happy."
 * 则输出"We%20are%20happy."
 */
public class T5
{
	/*
	 * 解题思路:
	 * 先遍历一遍数组 找到一共有多少个空格 在尾部添加2*空格个数的任意字符
	 * 令P1指向原末尾,P2指向延长后的末尾,两指针均从后往前遍历(P1开始)
	 * 每当P1遍历到一个字符时 将它复制到P2 两指针同时前移一位
	 * 当P1遍历到空格时 P1向前移一位 P2向前移动三位并填充02%
	 * 当P1与P2重合时 则结束
	 * 从后向前遍历是为了在改变P2所指向的内容时 不会影响到P1遍历原来的字符串内容 
	 */
	public String replaceSpace(StringBuffer str) 
	 {
		 int P1=str.length()-1;
		 for(int i=0;i<=P1;i++)
		 {
			 if(str.charAt(i)==' ')
			 {
				 str.append("  ");
			 }
		 }
		 int P2=str.length()-1;
		 while(P1!=P2)
		 {
			 if(str.charAt(P1)!=' ')
			 {
				 str.setCharAt(P2, str.charAt(P1));
				 P1--;
				 P2--;
			 }
			 else
			 {
				 P1--;
				 str.setCharAt(P2--, '0');
				 str.setCharAt(P2--, '2');
				 str.setCharAt(P2--, '%');
			 }
		 }
		 return str.toString();
	 }
}

面试题6:从尾到头打印链表

题目链接

import java.util.ArrayList;
import java.util.Collections;
import java.util.Stack;

/*
 * P58面试题6:从尾到头打印链表
 * 题目:输入一个链表的头结点,从尾到头反过来打印出每个节点的值
 */
public class T6
{
	/*
	 * 解法一:使用栈
	 * 由于栈的“后进先出特性” 对链表进行一次遍历后依次弹出
	 * 得到的顺序即为逆序
	 */
	public ArrayList<Integer> printListFromTailToHead1(ListNode listNode) 
	{
		Stack<Integer> stack=new Stack<Integer>();
		while(listNode!=null)
		{
			stack.add(listNode.val);
			listNode=listNode.next;
		}
		ArrayList<Integer> res=new ArrayList<Integer>();
		while(!stack.isEmpty())
		{
			res.add(stack.pop());
		}
		return res;
    }
	
	/*
	 * 解法二:使用递归
	 * 递归的本质就是一个栈结构 所以可以自然地想到用递归来实现
	 * 具体实现为:每访问到一个节点的时候,先递归输出它后面的节点,再输出该节点自身
	 * 但该方法若是输入的链表长度非常长时
	 * 会导致函数调用的层级过深
	 * 从而导致函数调用栈溢出(java.lang.StackOverflowError)
	 */
	public ArrayList<Integer> printListFromTailToHead2(ListNode listNode) 
	{
		ArrayList<Integer> res=new ArrayList<Integer>();
		if(listNode!=null)
		{
			res.addAll(printListFromTailToHead2(listNode.next));
			res.add(listNode.val);
		}
		return res;
	}
	
	/*
	 * 解法三:使用头插法
	 * 由于头插法的性质是每次插入在头部
	 * 所以使用头插法重新构建链表后即为逆序
	 * 注意点:
	 * 头结点是在头插法中使用的一个额外节点,这个节点不存储值
	 * 第一个节点就是链表的第一个真正存储值的节点
	 */
	public ArrayList<Integer> printListFromTailToHead3(ListNode listNode) 
	{
		ListNode head=new ListNode(-1);//头结点
		while(listNode!=null)
		{
			ListNode temp=new ListNode(listNode.val);
			temp.next=head.next;
			head.next=temp;
			listNode=listNode.next;
		}	
		ArrayList<Integer> res=new ArrayList<Integer>();
		head=head.next;
		while(head!=null)
		{
			res.add(head.val);
			head=head.next;
		}
		return res;
	}
	
	
	/*
	 * 解法四:使用Collection.reverse()
	 */
	public ArrayList<Integer> printListFromTailToHead4(ListNode listNode) 
	{
		ArrayList<Integer> res=new ArrayList<Integer>();
		while(listNode!=null)
		{
			res.add(listNode.val);
			listNode=listNode.next;
		}
		Collections.reverse(res);
		return res;
	}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章