把敬业变成习惯。短期来看是为了雇主,长期来看是为了自己。
1.题目:全排列问题
这种问题在算法题中应用很多,主要思路是使用递归来求,求n个数的全排列就是把第一个数固定后求n-1个数的全排列,不断递归到只有一个数
private static void Method1() {
disorder(array,0,array.length);
}
private static void disorder(int array[],int m,int n){
if (m==n){
for (int i=0;i<n;i++){
System.out.print(array[i]);
}
System.out.println();
return;
}else {
for (int i=m;i<n;i++){
swap(array,m,i);
disorder(array,m+1,n);
swap(array,m,i);
}
}
}
private static void swap(int[] array,int m,int n){
int temp=array[m];
array[m]=array[n];
array[n]=temp;
}
2.题目:纸牌三角形
A,2,3,4,5,6,7,8,9 共9张纸牌排成一个正三角形(A按1计算)。要求每个边的和相等。
下图就是一种排法
A
9 6
4 8
3 7 5 2
这样的排法可能会有很多。
如果考虑旋转、镜像后相同的算同一种,一共有多少种不同的排法呢?
请你计算并提交该数字。
这道题就是一个典型的全排列问题,但题目有要求说旋转、镜像算一种,那么你就要在最后的结果除以6,因为正三角旋转有3种情况,镜像有两种情况
static int[] first = new int[9];
static int[] s = new int[9];
static int sum = 0;
private static void Method1() {
seek(0);
System.out.println(sum / 6);//6是因为有3种旋转2种翻转
}
private static void seek(int code) {
if (code == 9) {
if (s[0] + s[1] + s[3] + s[5] == s[0] + s[2] + s[4] + s[8]
&& s[0] + s[1] + s[3] + s[5] == s[5] + s[6] + s[7] + s[8])
sum++;
return;
}
for (int i = 0; i < 9; i++) {
if (first[i] == 0) {
first[i] = 1;
s[code] = i + 1;
seek(code + 1);
first[i] = 0;
}
}
}
static int num = 0;
private static void Method2() {
int a[] = new int[]{1, 2, 3, 4, 5, 6, 7, 8, 9};
f1(a, 0);
System.out.println(num / 6);
}
public static void f1(int a[], int k) {
int q, w, e;
if (k == a.length - 1) {
q = a[0] + a[1] + a[2] + a[3];
w = a[3] + a[4] + a[5] + a[6];
e = a[6] + a[7] + a[8] + a[0];
if (q == w && w == e) num++;
}
for (int i = k; i < a.length; i++) {
System.out.println(i+" "+k);
{
int temp = a[i];
a[i] = a[k];
a[k] = temp;
}
f1(a, k + 1);
{
int temp = a[i];
a[i] = a[k];
a[k] = temp;
}
}
}
3.题目:给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的 两个 整数。你可以假设每种输入只会对应一个答案。但是,你不能重复利用这个数组中同样的元素。
示例:
给定 nums = [2, 7, 11, 15], target = 9
因为 nums[0] + nums[1] = 2 + 7 = 9
所以返回 [0, 1]
如果不可以组成目标数字则返回[-1,-1]
题目非常简单,只要使用for循环就能搞定
private static int[] getSum(int[] nums, int target) {
for (int i=0;i<nums.length-1;i++){
for (int j=i+1;j<nums.length;j++){
if (nums[i]+nums[j]==target){
System.out.println(i+" "+j);
return new int[]{i,j};
}
}
}
return new int[]{-1,-1};
}
但是你会觉得两层太麻烦了,一定有办法一遍完事。这样用到了hashmap,这种数据数据查询十分快,是一种用控件换时间的数据结构,因为如果存在两个满足条件的数的话,当循环到第二个数的时候便能打印出来,这样复杂度便降到了最低了。
public static int[] twoSum(int[] nums, int target) {
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < nums.length; i++) {
int complement = target - nums[i];
if (map.containsKey(complement)) {
System.out.println(map.get(complement)+" "+i);
return new int[] { map.get(complement), i };
}
map.put(nums[i], i);
}
throw new IllegalArgumentException("No two sum solution");
}
4.两数之和(二叉树)
/**
* 给定一个二叉搜索树和一个目标结果,如果 BST 中存在两个元素且它们的和等于给定的目标结果,则返回 true。
* 输入:
* 5
* / \
* 3 6
* / \ \
* 2 4 7
*
* Target = 9
*
* 输出: True
*/
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
}
现在找寻两个数字已经从数组转换成了二叉树,但是你可以使用类似的办法,将二叉树遍历添加到数组中或者列表中,然后进行查找
private static List<Integer> integers=new ArrayList<>();
private static boolean getSum(TreeNode root, int k) {
ergodic(root);
if(integers.size()==1){
if(integers.get(0)==k) return true;
else return false;
}
for (int i=0;i<integers.size()-1;i++){
for (int j=i+1;j<integers.size();j++){
if (integers.get(i)+integers.get(j)==k){
return true;
}
}
}
return false;
}
private static void ergodic(TreeNode root) {
if (root.left!=null){
ergodic(root.left);
}
integers.add(root.val);
if (root.right!=null){
ergodic(root.right);
}
}
5.数字反转
/**
* 给出一个 32 位的有符号整数,你需要将这个整数中每位上的数字进行反转。
* 示例:
* 输入: 123
* 输出: 321
*
* 输入: -123
* 输出: -321
*
* 输入: 120
* 输出: 21
*/
这道题有两个点需要注意,一是要注意负数的反转,二是要注意int类型的范围问题,比如-2147483412
两种解法,一种是将大数分割成两个数进行转换,因为Integer.parseInt()的范围比较小,超出范围便会出错,另一种是借助long类型
public static int reverse(int x) {
if (x>=0){
char[] chars=(x+"").toCharArray();
for (int i=0;i<chars.length/2;i++){
char c=chars[i];
chars[i]=chars[chars.length-i-1];
chars[chars.length-i-1]=c;
}
String s=new String(chars);
if (s.length()>=10){
String a=s.substring(0,s.length()/2);
String b=s.substring(s.length()/2);
double result=Integer.parseInt(a)*Math.pow(10,b.length())+Integer.parseInt(b);
int res=(int)result;
if (res==Integer.MAX_VALUE){
return 0;
}
return res;
}else {
return Integer.parseInt(s);
}
}else {
char[] chars=(x+"").toCharArray();
for (int i=1;i<=chars.length/2;i++){
char c=chars[i];
chars[i]=chars[chars.length-i];
chars[chars.length-i]=c;
}
String s=new String(chars);
if (s.length()>=10){
String a=s.substring(1,s.length()/2);
String b=s.substring(s.length()/2);
System.out.println(a+" "+b+" "+s.length()/2);
double result=Integer.parseInt(a)*Math.pow(10,b.length())+Integer.parseInt(b);
System.out.println(result);
int res=(int)-result;
if (res==Integer.MIN_VALUE){
return 0;
}
return res;
}else {
return Integer.parseInt(s);
}
}
public static int reverse(int x) {
long z = x;
String str = String.valueOf(Math.abs(z));
StringBuilder conStr = new StringBuilder();
int len = str.length();
while( len > 0){
conStr.append(str.charAt(len - 1));
len--;
}
Long l = Long.parseLong(conStr.toString());
if(l > Integer.MAX_VALUE){
return 0;
}
if(x >= 0)
return l.intValue();
else{
return -l.intValue();
}
}
但是你还是不满意,你觉得完全没必要这么麻烦,只要循环取个位数然后拼接到另一个数的个位数上就可以了嘛,然后中间放一个判断溢出的,怎么做呢
pop = x % 10;//取出来个位数
x /= 10;//把十位数变成个位数
temp = rev * 10 + pop;//拼接到另一个数上
rev = temp;
//循环此操作
那怎么判断是否溢出呢?如果temp=rev*10+pop溢出,那么rev>=IntMax/10,然后我们分情况进行处理
如果rev>IntMax/10,temp=rev*10+pop一定溢出
如果rev=IntMax/10,pop大于7才溢出
把逻辑写成程序
public int reverse(int x) {
int rev = 0;
while (x != 0) {
int pop = x % 10;
x /= 10;
if (rev > Integer.MAX_VALUE/10 || (rev == Integer.MAX_VALUE / 10 && pop > 7)) return 0;
if (rev < Integer.MIN_VALUE/10 || (rev == Integer.MIN_VALUE / 10 && pop < -8)) return 0;
rev = rev * 10 + pop;
}
return rev;
}
漂亮!