做做tx六道面试算法题,题目来自牛客

1) 洗牌算法:对52张牌洗牌,要求尽量洗乱,而且原牌不能在原位置上重复

洗牌算法是常见的随机问题:将1-52张扑克牌重新洗牌。

Fisher–Yates随机置乱算法也被称做高纳德置乱算法,通俗说就是生成一个有限集合的随机排列。Fisher-Yates随机置乱算法是无偏的,所以每个排列都是等可能的,当前使用的Fisher-Yates随机置乱算法是相当有效的,需要的时间正比于要随机置乱的数,不需要额为的存储空间开销。

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.println(Arrays.toString(shuffle(new int[]{1,2,3,4,5})));

	}
	//这里区分一下java中的随机数random.nextInt()与c++中的rand()
	//比如在10到99产生一个随机数
	//random.randInt(90)+10 rand()%(90)+10
	static int [] shuffle(int [] a){
		int n = a.length;
		Random random = new Random();
		int temp = 0;
		for(int i =a.length-1;i>=0;i--){
			int x = random.nextInt(i+1);
			temp = a[i];
			a[i]=a[x];
			a[x] = temp;
		}
		return a;
	}
}

这个算法随机选取一个随机数,然后与数组最后的元素进行交换,然后缩小数组范围,一直循环,知道最后一个。

2) 现在有n个微信群,每个群里面有2到m个人,设计一个数据结构存储这些信息,要求该结构能快速找出每一个人所在的所有的群Id。

这道题使用并查集即可:
https://www.acwing.com/problem/content/838/ 跟这题基本一致
在这里给一个模板:

(1)朴素并查集:

    int p[N]; //存储每个点的祖宗节点

    // 返回x的祖宗节点
    int find(int x)
    {
        if (p[x] != x) p[x] = find(p[x]);
        return p[x];
    }

    // 初始化,假定节点编号是1~n
    for (int i = 1; i <= n; i ++ ) p[i] = i;

    // 合并a和b所在的两个集合:
    p[find(a)] = find(b);

3) 数组a[N],存放了数字1至N-1,其中某个数字重复一次。写一个函数,找出被重复的数字。时间复杂度必须为O(N), 空间复杂度不能是O[N]。

这道题是剑指Offer的经典题型,这道题的时间复杂度要求o(N),一般我的思路就是先排序再遍历,计算a[i]与a[i+1]是否相等,相等就return。
这里给出两种解题思路:
一种就是上述:

class Solution {
    public int duplicateInArray(int[] nums) {
        if(nums==null||nums.length==1){
            return -1;
        }
        Arrays.sort(nums);
        for(int i = 0 ; i < nums.length-1; i++){
            if(nums[i]==nums[i+1]){
                return nums[i];
            }
        }
        return -1;
    }
}

第二种做法:
将当前位置的数值放到他的位置上去,比如{2,2,3,3,4},将nums[0]的数应该放到nums[2]上,即将该数组放到他在数组中和他角标相等的位置,每次都检查要交换的位置上的数值是否一样,如果一样,则重复,如果不一样,则交换。

时间复杂度分析:o(n)

 public int duplicateInArray(int[] nums) {
        int len = nums.length;
        if(nums==null||len==0)
            return -1;
        for(int i = 0;i<len;i++){
            while(nums[i]!=i){
                if(nums[i]==nums[nums[i]])
                    return nums[i];
                    
                int temp = nums[i];
                nums[i] = nums[temp];
                nums[temp] = temp;
            }
        }

        return -1;
    }

4) 现在有一个微信群,里面有n个人,每个人的id用整数int标示,现在要求找出id是对称数字的人出来,如3, 121, 12321。 请实现改查找函数,不能把整数转为字符串来判断。

public boolean find(int n){
		int res = 0;
		while(n!=0)
		{
			i=n%10;
			res=(res*10)+i;
			n/=10;
		}
		if(m==res){
			return true;
		}
		retrun false;
}

5) 给定一个字符串,如“1234”,请实现一个函数,把这个字符串转成10进制整型,不能用系统函数

系统函数的实现:
java.lang.Integer中有一个bai方法:valueOf(String s,int radix)

int res = Integer.valueOf(s,10);

上面这个不合题意,所以换一个。

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc  = new Scanner(System.in);
        String s = sc.nextLine();
        System.out.println(cal(s));

    }
    public static int cal(String s){
        int res = 0;
        for(int i = 0; i < s.length(); i++){
            res += (s.charAt(s.length()-1-i)-'0')*Math.pow(10,i);
        }
        return res;
    }
}

6) 有一个二叉树,每个节点的值是一个整数。写一个函数,判断这棵树中是否存在从根到叶子节点的一个路径,这个路径上所有节点之和为某一个值。存在返回1, 否则返回0。

力扣经典题
我们必须先了解二叉树的遍历框架
说到二叉树的遍历框架,很多人的脑海里立马蹦出来的就是前序、中序和后序遍历。但是机械地记住前中后序遍历没有太大意义,我们首先要掌握的是二叉树的递归思想

递归有两大要点:
反复调用自身
终止条件

二叉树结构上进行递归,则这两大要点变为:
递归调用自己两个子树
在叶结点处终止递归

调用子树的部分是重点。我们需要保证在子树上求解的是与原问题相同的子问题,才能递归调用自身。而终止条件可以放在最后作为细节考虑。


boolean hasPathSum(TreeNode root, int sum){
if(root==null){
 return false;

 }
 if(root.left==null&&root.right==null){
  return root.value==sum;
 }
 int target=sum-root.value;
 return hasPathSum(root.left, target)||hasPathSum(root.right, target);
}

okk !!! 希望对大家有所帮助!!!有问题评论区见
111

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值